Vercel
Deploy the fullstack target to Vercel serverless and fix the edge-incompatible features.
The vercel deploy target runs the app and the shared @repo/api backend as serverless functions - it auto-selects the fullstack architecture and hides separate (serverless can't host a long-running process). Several flag-gated features assume a persistent runtime, so swap them before you deploy.
Vercel has no startup hook, so init prepends a schema-prep step to the deployed app's vercel.json buildCommand (it preserves any existing command, defaulting to pnpm build). The non-demo step is pnpm -F @repo/database migrate - additive migrations run as part of every build, not at boot.
Deploy
Provision managed services. Serverless functions are stateless, so every dependency must be a hosted service:
- Postgres: Neon or Supabase (any connection-pooled Postgres
DATABASE_URL). - Cache / rate limiting: Upstash Redis (HTTP-based; a self-hosted Redis connection won't survive between invocations).
- Background jobs: a hosted Inngest app (
INNGEST_*keys). See Background jobs.
Set environment variables in the Vercel project. At minimum: BASE_URL (your production URL), BETTER_AUTH_SECRET (min 32 chars), DATABASE_URL, the cache pair, and the INNGEST_* trio. Full list in Environment variables.
Connect the repository in the Vercel dashboard (or run vercel deploy). The build runs the prepended schema-prep step, then the app build - no separate migrate command needed.
Verify the deployed URL serves the app and /api/* routes. The shared @repo/api backend mounts in-process through the app's catch-all API route - there is no separate backend service to deploy.
Edge-incompatible features
These features default to runtime-safe values, but if you enabled a long-running variant locally, switch it before deploying:
| Feature | Incompatible setting | Fix on Vercel |
|---|---|---|
| Storage | config.storage.provider: "local" | Keep "s3" (the default) - see Storage |
config.email.provider: "smtp" | Set to "resend" or "ses" - see Email | |
| Cache | self-hosted Redis (ioredis) | Use the Upstash provider - see Caching |
| Content API | gitCommit on with config.contentApi.enabled | Disable gitCommit (the filesystem is read-only) |
When a flag is off, its routes and UI are hidden - disabling the feature removes the incompatibility entirely. The shipped defaults (storage.provider: "s3", contentApi.enabled: false) are already Vercel-safe.
Never pass --demo for a real deployment - the schema step becomes a destructive reset && push --force that wipes the database on every build.