Deployment

Deployment

The generator retains one platform configuration based on --target. Confirm target in nextdevtpl.generated.json, apply production migrations and environment variables, then follow the matching flow.

Shared release gate

pnpm install --frozen-lockfile
pnpm lint
pnpm typecheck
pnpm test:run
pnpm build

Set both NEXT_PUBLIC_APP_URL and BETTER_AUTH_URL to the production URL. Update OAuth callbacks, payment webhooks, Inngest, storage CORS, and other provider dashboards to use the same domain.

Server

The server target requires Node.js 24, pnpm 10, PostgreSQL, and systemd.

  1. Fill .env.production and keep it in a protected server directory.
  2. Generate and review the initial migration with pnpm db:generate:init.
  3. Load production variables and run pnpm deploy:server:build.
  4. Upload .release/ and adjust deploy/server/nextdevtpl.service for the real user and path.
  5. Terminate TLS with Nginx, Caddy, or another proxy and forward original protocol and host headers.

See deploy/server/README.md for file-level instructions.

Docker Compose

Compose contains PostgreSQL, a one-shot migration service, and the app. The database uses a named volume.

docker compose --env-file .env.production up -d --build

At minimum, replace POSTGRES_PASSWORD, BETTER_AUTH_SECRET, and site URLs. The app starts only after migrate succeeds. Back up the named volume or external database before upgrades. See deploy/docker/README.md.

Vercel

  1. Import the project into Vercel with Node.js 24 and pnpm.
  2. Configure variables retained in the generated .env.example for each environment.
  3. Run pnpm db:migrate locally or in a controlled single-instance release job.
  4. Deploy and configure OAuth, payment, and Inngest callbacks.
  5. Run the health check against the production domain.

Do not put migrations in Vercel's buildCommand; concurrent builds can execute them more than once. Vercel works well with Neon, S3-compatible storage, Upstash, and Inngest, subject to the generated selection.

Cloudflare Workers

The Cloudflare target uses OpenNext. It generates open-next.config.ts, the Worker entry, wrangler.jsonc, and cf:* scripts, then adds R2, AI, Email, Workflow, and Rate Limiting bindings when selected.

  1. Create the real resources and check service and bucket names in wrangler.jsonc.
  2. Add DATABASE_URL, auth secrets, and provider credentials with wrangler secret put.
  3. Generate Worker types and build:
pnpm cf:check
pnpm cf:types
pnpm cf:build
pnpm exec wrangler deploy --dry-run --minify
  1. Deploy:
pnpm cf:deploy

The 3.x Worker target uses PostgreSQL through Neon HTTP or Hyperdrive. D1 is outside the 3.x support scope. Generated Worker projects use a console logger and remove Pino's Node file-writing dependencies.

Production check

All four targets expose /api/health:

pnpm deploy:check -- https://your-domain.example/api/health

After it returns HTTP 200 with status: healthy, verify login, database access, and each selected payment, mail, storage, AI, jobs, and rate-limit flow. The health response never returns secret values.

On this page