← All lessons
Lesson 19 · Advanced

Deployment

Build, ship, and monitor. From Vercel one-click to self-hosted on a Node server.

Build for production

npm run build
npm start

build produces a production bundle and prints a route-by-route summary: which pages are static (●), dynamic (ƒ), or use ISR (◐). Use it to sanity-check your rendering choices before pushing.

Environment variables

  • Server-only: process.env.STRIPE_SECRET — never sent to the browser.
  • Public (prefixed NEXT_PUBLIC_): inlined at build time and visible in the browser bundle.
  • Local dev values go in .env.local. Never commit secrets.
// .env.local
DATABASE_URL=postgres://...
NEXT_PUBLIC_SITE_URL=https://example.com

Deploy on Vercel

Vercel is the smoothest path: connect a Git repo, push to main, get a URL. ISR, image optimization, edge middleware and preview deployments work out of the box. Environment variables go in the project settings.

Self-hosting

Next.js apps are just Node servers. To deploy anywhere:

# build once, then run a long-lived Node process
npm ci
npm run build
NODE_ENV=production node node_modules/next/dist/bin/next start -p 3000

Or use the **standalone output** to ship a much smaller server with only the files you need:

// next.config.mjs
export default { output: "standalone" };

After next build, the .next/standalone/ folder is a self-contained Node app. Combine it with .next/static and public/ in a container. This is the recommended Docker pattern.

What to check post-deploy

  • Open the deployed site and Network panel — confirm pages stream and images serve as AVIF/WebP.
  • Hit a 404 path to check not-found.js renders.
  • If you use ISR or revalidation, manually trigger a revalidate and confirm the page updates.
  • Run Lighthouse on the LCP page. The hero image should have priority.
Note: Production rendering can differ from dev. The build output is the source of truth — read it carefully when something behaves unexpectedly in production.

Try it

You want to deploy in a small Docker image. Add the option to next.config.mjs that produces a standalone server bundle.

Need a hint?

There is a single `output` config option whose value is a string.

Quiz

Pick the best answer. You only get one shot per question.

1. Which env var prefix exposes a value to the browser bundle?

2. What does `output: "standalone"` produce?

3. After `npm run build`, where do you confirm which pages are static vs. dynamic?