Open-source, self-hostable tracker for movies, series, anime, manga, and webtoons — community-owned, so it can never be taken away from its users.
TV Time shut down and deleted everyone's history. Trackt exists so that never happens again: full export at any time, a public API from day one, and self-hosting in one command.
See the full product spec in docs/PRD.md and the current status in docs/ROADMAP.md.
- Data portability is sacred — open export formats, public REST API (OpenAPI docs on every instance).
- Self-hostable in one command —
docker compose up. - Open source so hosted forks contribute back.
- Community catalog — users can add what the big databases don't have (webtoons especially).
cp .env.example .env # set AUTH_SECRET (openssl rand -base64 32), optionally TMDB_API_KEY
docker compose up -d
open http://localhost:3000Migrations run automatically on boot; upgrading is docker compose pull && docker compose up -d. A nightly pg_dump sidecar is included (--profile backup), and optional MinIO for S3-compatible cover storage (--profile minio). TLS is not bundled — put Caddy in front, or deploy on a platform that terminates TLS for you.
Requirements: Node 22+, pnpm 11 (corepack enable — the exact version is pinned in package.json's packageManager), Docker.
pnpm install
docker compose -f docker-compose.dev.yml up -d # Postgres 16 (:5432), Redis, catalog Postgres (:5433)
pnpm db:migrate # apply schema (after pnpm build once)
pnpm db:seed # fixture catalog so search has data
pnpm dev # web :3000, api :3001, catalog :3002, worker — hot reloadNo .env needed in development — every variable has a dev default (see packages/shared/src/env.ts). The web dev server proxies /api, /docs, and health endpoints to the API.
| Command | What it does |
|---|---|
pnpm dev |
run everything in watch mode (Turborepo) |
pnpm build |
build all apps and packages |
pnpm test |
run vitest suites |
pnpm lint / pnpm typecheck / pnpm format |
the usual suspects |
pnpm db:generate |
generate a migration from schema changes (drizzle-kit) |
pnpm db:migrate |
apply migrations to DATABASE_URL |
pnpm db:seed |
insert the dev fixture catalog (idempotent) |
apps/
web/ TanStack Start PWA (SSR for public pages, installable on mobile)
api/ Fastify public REST API — OpenAPI generated from Zod schemas at /docs
worker/ BullMQ background jobs: importers, notifications (none built yet)
discord/ Optional Discord bot (discord.js): news feeds per channel; starts only with DISCORD_BOT_TOKEN
catalog/ Central slim catalog service, and the News surface (project-operated, not self-hosted)
packages/
shared/ Zod schemas, shared types, env validation — single source of truth
client/ The API data layer every client shares: fetch + Zod + React Query, no UI
db/ Drizzle ORM schema + migrations (PostgreSQL 16)
providers/ Parked: metadata providers (future per-instance enrichment)
- Central slim catalog (ADR-0001): a project-operated service holds the shared catalog of redistributable facts (titles, synonyms, years, genres, counts, external IDs), keyed by deterministic canonical media IDs (UUIDv5) that every instance derives identically with zero coordination.
- Federated search, no mirror (ADR-0002): an instance queries its local Postgres and the central catalog live, in parallel, merges by canonical id, and writes central-only hits into local
mediaon first sight. Every central call is timeout-bounded and degrades rather than failing — an unreachable catalog costs you central results, never a 500. - One media row is one trackable unit (ADR-0003): a
series/animerow is a single season with its own canonical ID and onepart_count; there is no parent show row. ADR-0004 adds the typedsequel/adaptation/spinoff/relatededges that reconnect them, stored one direction only with the inverse rendered as a derived label. - News (ADR-0005): articles live only in the central catalog and are published by the project operator through a human-gated admin path; instances read
/newslive and degrade to an empty feed if the catalog is unreachable. Nothing is mirrored, and self-hosters run no news infrastructure. - Shard-friendly schema (PRD §5): UUIDs everywhere,
user_idon every user-owned table, no cross-user joins in hot paths. Scaling ladder: partitioning → read replicas → Citus, without an app rewrite. - Monolith image: one container runs API (public port), web SSR, and worker; the API proxies non-API routes to the SSR server. Separate processes remain the advanced path.
- Config via env vars only, Zod-validated at startup with actionable errors.
Catalog entries reference external IDs from TMDB, AniList, and TVmaze. Optional per-instance enrichment may use the TMDB API with the instance's own key; this product uses the TMDB API but is not endorsed or certified by TMDB.
GPL-3.0-only, with one additional permission under GPLv3 §7: the mobile client's binary may be distributed through app stores whose terms would otherwise conflict with §§4–6. Everything else is unchanged — the source, including the mobile client's, stays GPL-3.0-only.