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:
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | yes | PostgreSQL connection string. For Supabase, use the transaction pooler (port 6543) with ?pgbouncer=true&connection_limit=1 |
JWT_ACCESS_SECRET | yes | Secret for signing access tokens (32+ chars) |
JWT_REFRESH_SECRET | yes | Secret for signing refresh tokens (32+ chars) |
GOOGLE_CLIENT_ID | yes* | Google OAuth client ID |
GOOGLE_CLIENT_SECRET | yes* | Google OAuth client secret |
GOOGLE_CALLBACK_URL | yes* | Must match the authorized redirect URI |
COOKIE_SECURE | no | true in production (cookies only over HTTPS) |
COOKIE_DOMAIN | no | Cookie domain; omit for localhost |
COOKIE_SAMESITE | no | lax (default) or none (cross-site clients, requires COOKIE_SECURE=true) |
CLIENT_SUCCESS_URL | no | Where users land after Google sign-in |
CORS_ORIGINS | no | Comma-separated extra client origins allowed by CORS |
ACCESS_TOKEN_TTL | no | Access token lifetime (default 15m) |
REFRESH_TOKEN_TTL | no | Refresh token lifetime (default 30d) |
PORT | no | HTTP 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:3300Deploy to Vercel + Supabase
-
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 -
Vercel — API (
apps/api/vercel.jsonis already configured for serverless). Add a project rooted atapps/apiand set these env vars:DATABASE_URL(transaction pooler, port6543,?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. -
Vercel — docs (
apps/docs/vercel.jsonis already configured). Add a project rooted atapps/docs; no env vars needed. -
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