Building and deploying

Ship it without leaking a secret, and know what to look at once it is live.

16of 16
≈ 11Min read
7Parts

Two kinds of environment variable

and the prefix that decides
# .env.local — your machine, never committed
DATABASE_URL=postgres://localhost:5432/doors
STRIPE_SECRET_KEY=sk_live_…
NEXT_PUBLIC_SITE_URL=https://domvybe.com

// server component, action, route handler, middleware
process.env.DATABASE_URL          // fine

// client component
process.env.DATABASE_URL          // undefined
process.env.NEXT_PUBLIC_SITE_URL  // works — and is in the JavaScript bundle
NEXT_PUBLIC_ means public

The value is inlined into the bundle at build time. Anyone can read it in devtools. A key with that prefix is not a secret, whatever the provider called it — and changing it needs a rebuild, not a restart.

Which file, and when

Commit a .env.example with every key and a dummy value. It is the only documentation of what the project needs that stays correct.

FileLoaded
.envAlways — for defaults that are not secret
.env.localAlways except in tests — gitignored, for your machine
.env.development / .env.productionPer NODE_ENV
The platform’s own variablesIn production, and they win

The build

  • npm run build must pass before you push. Type errors and lint errors fail it by default.
  • The build reads environment variables — a missing one at build time is not the same failure as a missing one at runtime.
  • Static export is right for a purely static site and wrong for everything in this course.
and the three ways to run what it produced
npm run build && npm start        # a Node server — the default

# output: "standalone"  → .next/standalone, a minimal server for a container
# output: "export"      → a folder of static files, and NO server:
#                         no server actions, no route handlers, no ISR

Where it runs

It is a Node application. Anywhere that runs Node and lets you set environment variables will run it; the differences are in how much of the caching works without configuration.

  • Vercel — made by the same people; every feature works on day one.
  • A container (Fly, Railway, Render, your own Kubernetes) — output: "standalone", a Dockerfile, node server.js.
  • Cloudflare / Netlify — adapters, with occasional gaps around ISR and the Node runtime.
  • Static hosting — only with output: "export".

A checklist before the first deploy

  • npm run build passes locally, with the production environment variables set.
  • .env* is gitignored, and every secret is set on the platform instead.
  • No NEXT_PUBLIC_ variable holds anything private.
  • The database is reachable from the platform, with a connection limit that matches a serverless environment.
  • A real metadataBase, a favicon, a robots.txt and a sitemap.
  • Error tracking installed. A 500 nobody hears about is a bug that lives for months.

Watch it after

  • The build output, every deploy: a route that turned dynamic, a chunk that doubled.
  • Error rate and latency, with an alert, not a dashboard you remember to open.
  • Core Web Vitals from real visitors, not only from your laptop.
  • The database: connection count, slow queries, and the pool.

And keep the rollback cheap

Every platform can redeploy the previous build in one click. The fastest fix for a bad release is the previous release — then find out what happened, without the pressure of production being broken.

Practice