August 2026
Games DB
A personal PC games catalogue that indexes Steam's entire storefront into Postgres, so browsing, filtering, and search never touch Steam's own rate-limited API.

- Role
- Solo build — frontend, backend, infrastructure
- Stack
- Next.js, TypeScript, Tailwind, Postgres, Drizzle, Auth.js, Vercel, Docker
What it brings
- Its own index of Steam's catalogue — 245,025 appids, 14,621 hydrated with full detail — because Steam has no /discover or /trending endpoint to browse against.
- Search runs on a Postgres trigram index (pg_trgm), not on Steam.
- One scheduled job — a monthly GitHub Actions cron refreshes prices — plus three CLI jobs (catalogue sync, list sync, hydration) run by hand. Hydration, price refresh, and list sync each take a Postgres advisory lock so two copies can't run at once; catalogue sync does not need one.
- GitHub OAuth sign-in for a personal library; browsing and search work for anyone, signed in or not.
Technical design
HTTPS, rate limited
Client
Next.js 16 App Router
React Server Components
Server
server/ modules
Catalogue, browse, detail, library, account.
Auth.js
server/steam
Its own rate limiter and TTL cache.
Data
Postgres (Neon)
Drizzle ORM
Four checked-in migrations.
pg_trgm GIN index
On game.name.
External
Steam Web API
Server Components
Drizzle
- Search is Postgres, not a search service. One pg_trgm GIN index on game.name covers 245,025 rows. Nothing to keep in sync, and no second datastore to pay for.
- Migrations are generated and checked in. db/migrations holds all four SQL files, and the pg_trgm extension is created by migration 0003 — not by a manual step someone has to remember against a new database.
- The Steam client owns its own rate limiter and cache. A page render cannot fan out into an unbounded number of upstream calls, whatever the page asks for.