Self-hosting

Run the Peridot ID API yourself

Requirements

  • Node.js 20+
  • pnpm
  • PostgreSQL 16+ (Supabase works great)

Refresh-token state lives in the sessions table, so PostgreSQL is the only datastore — no Redis needed.

Environment variables

All configuration is loaded from .env in the API package. Copy apps/api/.env.example to apps/api/.env and fill it in:

VariableRequiredDescription
DATABASE_URLyesPostgreSQL connection string. For Supabase, use the transaction pooler (port 6543) with ?pgbouncer=true&connection_limit=1
JWT_ACCESS_SECRETyesSecret for signing access tokens (32+ chars)
JWT_REFRESH_SECRETyesSecret for signing refresh tokens (32+ chars)
GOOGLE_CLIENT_IDyes*Google OAuth client ID
GOOGLE_CLIENT_SECRETyes*Google OAuth client secret
GOOGLE_CALLBACK_URLyes*Must match the authorized redirect URI
COOKIE_SECUREnotrue in production (cookies only over HTTPS)
COOKIE_DOMAINnoCookie domain; omit for localhost
COOKIE_SAMESITEnolax (default) or none (cross-site clients, requires COOKIE_SECURE=true)
CLIENT_SUCCESS_URLnoWhere users land after Google sign-in
CORS_ORIGINSnoComma-separated extra client origins allowed by CORS
ACCESS_TOKEN_TTLnoAccess token lifetime (default 15m)
REFRESH_TOKEN_TTLnoRefresh token lifetime (default 30d)
PORTnoHTTP port (default 3301)

* Google endpoints return 503 until these are set. Create credentials at the Google Cloud console and add GOOGLE_CALLBACK_URL as an authorized redirect URI.

Local development with Docker

docker compose up -d          # Postgres
pnpm install
pnpm db:migrate               # apply Prisma migrations
pnpm dev                      # API on http://localhost:3301, docs on http://localhost:3300

Deploy to Vercel + Supabase

  1. Supabase — create a project, then run migrations against it (use the session pooler, port 5432, for migrations):

    DATABASE_URL="postgresql://postgres.<ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres" \
      pnpm --filter @peridot/api db:migrate deploy
  2. Vercel — API (apps/api/vercel.json is already configured for serverless). Add a project rooted at apps/api and set these env vars: DATABASE_URL (transaction pooler, port 6543, ?pgbouncer=true), JWT_ACCESS_SECRET, JWT_REFRESH_SECRET, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_CALLBACK_URL, COOKIE_SECURE=true, COOKIE_SAMESITE, CLIENT_SUCCESS_URL, CORS_ORIGINS.

  3. Vercel — docs (apps/docs/vercel.json is already configured). Add a project rooted at apps/docs; no env vars needed.

  4. Attach your custom domains and point DNS at Vercel.

Production build

pnpm build
pnpm --filter @peridot/api db:migrate deploy
pnpm --filter @peridot/api start

On this page