@lorenzopant/tmdb
v2.2.0
Published
A completely type-safe The Movie Database (TMDB) API wrapper for typescript applications.
Maintainers
Readme
🍿 @lorenzopant/tmdb
A TypeScript-first lightweight client for The Movie Database (TMDB) API.
This package is open-source and will be updated regularly with new features. Feel free to open pull requests on the project repository.
- 📦 Full TypeScript support
- 🔥 Simple and tiny wrapper
- 🚀 Designed for server-side and frontend use (NextJS, React, Vue, etc.)
Full documentation is available at @lorenzopant/tmdb
Installation
npm install @lorenzopant/tmdb
// or
pnpm add @lorenzopant/tmdb
// or
yarn add @lorenzopant/tmdbQuick Start
import { TMDB, TMDBError } from "@lorenzopant/tmdb";
const tmdb = new TMDB(process.env.TMDB_ACCESS_TOKEN!);
const movie = await tmdb.movies.details({ movie_id: 550 });
console.log(movie.title); // "Fight Club"Namespaces
Every namespace maps directly to a TMDB API section. All methods are fully typed.
| Namespace | Description |
| ------------------------ | ----------------------------------------------------------------- |
| tmdb.movies | Movie details, credits, images, videos, recommendations, and more |
| tmdb.movie_lists | Now Playing, Popular, Top Rated, Upcoming |
| tmdb.tv_series | TV series details, credits, seasons, episode groups |
| tmdb.tv_lists | Airing Today, On The Air, Popular, Top Rated TV |
| tmdb.tv_seasons | Season details, credits, images |
| tmdb.tv_episodes | Episode details, credits, images |
| tmdb.tv_episode_groups | Episode group details |
| tmdb.search | Search movies, TV shows, people, collections, keywords |
| tmdb.discover | Discover movies and TV shows by filter |
| tmdb.trending | Trending movies, TV, and people |
| tmdb.people | Person details, credits, images, translations |
| tmdb.people_lists | Popular people |
| tmdb.collections | Collection details and images |
| tmdb.companies | Company details, alternative names, images |
| tmdb.credits | Credit details |
| tmdb.genres | Movie and TV genre lists |
| tmdb.keywords | Keyword details and associated movies |
| tmdb.certifications | Movie and TV certifications per region |
| tmdb.changes | Recent content changes |
| tmdb.configuration | TMDB configuration, countries, languages, timezones |
| tmdb.find | Find resources by external ID (IMDb, TVDB, etc.) |
| tmdb.networks | TV network details |
| tmdb.watch_providers | Watch providers by region |
| tmdb.lists | User-created list management |
| tmdb.account | Account details and user lists |
| tmdb.authentication | Token-based authentication flows |
| tmdb.guest_sessions | Guest session rated movies/TV/episodes |
| tmdb.reviews | Review details |
| tmdb.images | Image URL builder (see below) |
| tmdb.v4 | TMDB API v4 (auth, account, lists — requires JWT) |
Constructor Options
const tmdb = new TMDB(accessToken, {
language: "en-US", // ISO 639-1: default language for all requests
region: "US", // ISO 3166-1: default region for all requests
timezone: "America/New_York", // default timezone for TV airing queries
logger: true, // enable built-in request/response logging
deduplication: true, // deduplicate concurrent identical requests (default: true)
rate_limit: true, // auto-queue requests to stay within TMDB rate limits
cache: true, // enable in-memory TTL-based response caching
images: {
secure_images_url: true,
default_image_sizes: { posters: "w500", backdrops: "w780" },
},
});logger
// Built-in console logger
const tmdb = new TMDB(token, { logger: true });
// Custom logger function
const tmdb = new TMDB(token, {
logger: (entry) => {
if (entry.type === "response") {
console.log(`[TMDB] ${entry.endpoint} → ${entry.status} (${entry.durationMs}ms)`);
}
},
});rate_limit
Automatically queues requests to stay within TMDB's API limits (~40 req/s). Useful for bulk scripts.
// Default limits
const tmdb = new TMDB(token, { rate_limit: true });
// Custom budget
const tmdb = new TMDB(token, { rate_limit: { max_requests: 30, per_ms: 1_000 } });cache
In-memory TTL-based caching for GET requests. Entries expire lazily on access.
// 5-minute TTL, no size limit (defaults)
const tmdb = new TMDB(token, { cache: true });
// Custom TTL and bounded size
const tmdb = new TMDB(token, {
cache: {
ttl: 60_000, // 60 seconds
max_size: 500, // evict oldest entry when limit is reached
excluded_endpoints: ["/trending", /\/discover\//],
},
});
// Runtime cache controls
tmdb.cache?.invalidate("/movie/now_playing"); // remove one entry
tmdb.cache?.clear(); // remove all entries
console.log(tmdb.cache?.size); // number of cached entriesttl can also be a function that decides each entry's lifetime once, when the response is stored. It receives a CacheTTLContext — { key, endpoint, params, data } — and returns milliseconds. Returning 0 or less skips caching that response; a function that throws or returns a non-finite number never fails the request — the response is simply not cached and the problem is reported through logger. Excluded endpoints never reach the function.
const DAY = 86_400_000;
const tmdb = new TMDB(token, {
cache: {
max_size: 5000,
ttl: ({ endpoint, data }) => {
// Feeds, search, lists, … — one day
if (!/^\/(movie|tv)\/\d+$/.test(endpoint)) return DAY;
const d = data as { release_date?: string; first_air_date?: string; status?: string };
const released = d.release_date || d.first_air_date;
const ageDays = released ? (Date.now() - Date.parse(released)) / DAY : 0;
if (!released || ageDays < 90) return DAY; // recent or unreleased
if (d.status === "Returning Series") return 30 * DAY;
return 90 * DAY;
},
},
});interceptors
Hook into every request or response globally.
const tmdb = new TMDB(token, {
interceptors: {
request: (ctx) => {
// Inject a param into every request
return { ...ctx, params: { ...ctx.params, include_adult: false } };
},
response: {
onSuccess: (data) => {
myAnalytics.track("tmdb_response", data);
},
onError: (error) => {
Sentry.captureException(error);
},
},
},
});Examples
Movie details
const movie = await tmdb.movies.details({ movie_id: 550 });
console.log(movie.title); // "Fight Club"
console.log(movie.release_date); // "1999-10-15"append_to_response — typed overloads
Fetch related data in a single request. The return type is automatically extended with the appended fields.
const movie = await tmdb.movies.details({
movie_id: 550,
append_to_response: ["credits", "videos"],
});
// TypeScript knows these are present:
console.log(movie.credits.cast[0].name);
console.log(movie.videos.results[0].key);Search
const results = await tmdb.search.movies({ query: "Inception", language: "en-US" });
console.log(results.results[0].title); // "Inception"TV series
const show = await tmdb.tv_series.details({ series_id: 1396 });
console.log(show.name); // "Breaking Bad"
const season = await tmdb.tv_seasons.details({ series_id: 1396, season_number: 1 });
console.log(season.episodes.length);Discover
const action = await tmdb.discover.movies({
with_genres: "28",
sort_by: "vote_average.desc",
"vote_count.gte": 1000,
});Trending
const trending = await tmdb.trending.movies({ time_window: "week" });Image URLs
const movie = await tmdb.movies.details({ movie_id: 550 });
// Build a full URL from a path
const posterUrl = tmdb.images.poster(movie.poster_path!, "w500");
const backdropUrl = tmdb.images.backdrop(movie.backdrop_path!, "w1280");
// Or enable auto-enrichment so all image paths in every response are resolved automatically
const tmdb = new TMDB(token, {
images: { autocomplete_images: true, secure_images_url: true },
});Standalone image URL builder
Only need the image URL builder and not the rest of the SDK? Import ImageAPI from the
@lorenzopant/tmdb/image subpath. It ships as its own ~3.4 kB bundle with no TMDB client and no
endpoint code, so you don't pull in the full SDK:
import { ImageAPI } from "@lorenzopant/tmdb/image";
const images = new ImageAPI({ secure_images_url: true });
const posterUrl = images.poster("/abc123.jpg", "w500");
const backdropUrl = images.backdrop("/def456.jpg", "w1280");ImageAPI needs no API token — it only builds URLs from paths.
Error handling
import { TMDB, TMDBError } from "@lorenzopant/tmdb";
try {
const movie = await tmdb.movies.details({ movie_id: 0 });
} catch (error) {
if (error instanceof TMDBError) {
console.error(error.message); // human-readable message
console.error(error.http_status_code); // e.g. 404
console.error(error.tmdb_status_code); // TMDB-specific status code
}
}TMDB API v4 (requires JWT access token)
const tmdb = new TMDB(jwtAccessToken);
const lists = await tmdb.v4.lists.list({ account_id: "me" });CLI
The package includes a tmdb command for quick lookups from the terminal:
export TMDB_BEARER_TOKEN=your_read_access_token # or: npx @lorenzopant/tmdb config set-token <token>
npx @lorenzopant/tmdb search inception
npx @lorenzopant/tmdb movie 27205 --append credits
npx @lorenzopant/tmdb tv top-rated
npx @lorenzopant/tmdb trending movie --week
npx @lorenzopant/tmdb discover movie --genre "science fiction" --sort rating
npx @lorenzopant/tmdb movie 550 --json | jq .titleThe CLI is bundled separately (dist/cli.mjs), so the SDK keeps zero runtime dependencies. See the CLI guide for every command and option.
Requirements
- Node.js 20+
- Works in frontend frameworks (React, Vue, Next.js) — never expose your access token to the browser in production
License
MIT
