Building and Deploying a Next.js App
Shipping a Next.js app means moving from next dev, which compiles pages on demand and keeps helpful error overlays, to next build, which produces an optimized production artifact: statically generated pages, server bundles for dynamic routes, and a .next directory that next start or a serverless platform can run. Understanding what happens during this transition — and where your app will actually run — is the difference between a smooth release and a 2am rollback.
Cricket analogy: It's like the difference between an IPL net session, where a batter faces throwdowns and adjusts technique freely, and the actual final at Narendra Modi Stadium, where every delivery counts and there's no redo.
Preparing Your App for Production
Running next build type-checks the project, lints it (unless disabled), and generates output per route based on its rendering mode: static HTML for pages without dynamic data needs, server functions for pages using fetch with dynamic options or cookies()/headers(), and pre-rendered params for generateStaticParams. The build also produces a .next/build-manifest.json and route-level JavaScript chunks, so reviewing the build output summary (which routes are Static ○, SSG ●, or Dynamic λ) tells you exactly how each page will behave in production before you deploy.
Cricket analogy: It's like a team management sheet before a Test match listing which players are confirmed starters, which are on standby, and which are ruled out — the build output is that same clarity for each route.
Environment Variables and Configuration
Next.js reads environment variables from .env.local, .env.production, and platform-level settings, but only variables prefixed with NEXT_PUBLIC_ are inlined into the client bundle at build time — everything else stays server-only. This means secrets like database URLs or API keys are safe by default, but it also means changing a NEXT_PUBLIC_ value requires a full rebuild, not just a redeploy of the same artifact, because the value is baked into the JavaScript at build time rather than read at runtime.
Cricket analogy: It's like the difference between a player's public jersey number, printed on the kit before the season starts, and their private medical file, which stays with the team physio and is never printed anywhere public.
Rule of thumb: if a value must never be visible in browser devtools, never prefix it with NEXT_PUBLIC_. If you change a NEXT_PUBLIC_ variable, you must rebuild — restarting the server with a new .env file alone will not pick it up.
Choosing a Deployment Target
Next.js supports several deployment models: fully managed platforms like Vercel that understand ISR, Edge Middleware, and Image Optimization natively; a Node.js server started with next start, suitable for traditional VMs or containers; and output: 'standalone' in next.config.js, which traces only the dependencies actually used and copies them into a minimal .next/standalone folder ideal for Docker images. The right choice depends on whether you need platform-specific features like on-demand ISR revalidation, how much infrastructure control your team wants, and cost constraints at scale.
Cricket analogy: It's like choosing between playing for a franchise with full backroom staff and analytics in the IPL versus running your own club side where you manage the ground, kit, and logistics yourself.
Deploying to Vercel
Connecting a GitHub repository to Vercel triggers automatic builds on every push: each pull request gets a unique preview deployment URL with its own isolated environment variables, and merges to the production branch trigger a production deployment with atomic, instant rollback if something breaks. Vercel also handles Incremental Static Regeneration behind the scenes, invalidating and regenerating cached pages on-demand without you managing a cache layer yourself, and it automatically applies Image Optimization and Edge Middleware without extra configuration.
Cricket analogy: It's like the DRS (Decision Review System) giving an instant, reliable review and reversal on the field — a bad production deploy on Vercel can be rolled back just as fast and cleanly.
# Standard production build and start
npm run build
npm run start
# Vercel CLI: deploy a preview, then promote to production
npx vercel
npx vercel --prodSelf-Hosting with Docker
For teams that need Kubernetes, on-premise infrastructure, or a specific cloud provider, setting output: 'standalone' in next.config.js produces a minimal server bundle with only the required node_modules traced in, which keeps Docker images small — often under 150MB versus over 1GB for a naive copy of the whole project. The resulting image runs node server.js directly, includes its own lightweight HTTP server, and still needs the public and .next/static folders copied in separately since standalone output does not include static assets by default.
Cricket analogy: It's like packing a touring squad's kit bag with only what's needed for an away series — bats, pads, and specific gear — rather than shipping the entire home ground's equipment room.
Standalone output does not automatically include the public/ folder or .next/static — you must add explicit COPY instructions for both in your Dockerfile, or requests for images, fonts, and client JS chunks will 404 in production.
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]next buildcompiles a production artifact and reports each route's rendering mode (Static, SSG, or Dynamic) in the build output summary.- Only variables prefixed NEXT_PUBLIC_ are inlined into the client bundle; changing one requires a full rebuild, not just a restart.
- Vercel gives automatic preview deployments per pull request and atomic, instant rollback for production deployments.
output: 'standalone'in next.config.js traces only required dependencies, producing a much smaller Docker image than copying the full project.- Standalone builds do not include public/ or .next/static automatically — Dockerfiles must copy them in explicitly.
- Self-hosting trades managed conveniences like ISR revalidation and Edge Middleware for full infrastructure control.
- Always verify the build output summary before deploying so you know exactly which pages are static versus server-rendered in production.
Practice what you learned
1. Which command produces the optimized production build in a Next.js project?
2. Which environment variable prefix makes a value accessible in client-side JavaScript?
3. What does setting output: 'standalone' in next.config.js primarily achieve?
4. When you change a NEXT_PUBLIC_ environment variable's value, what must you do for it to take effect?
5. What happens by default when you deploy a pull request branch to Vercel?
Was this page helpful?
You May Also Like
Next.js Performance Optimization
Practical techniques for making Next.js apps fast: image and font optimization, code splitting, caching strategies, and Core Web Vitals.
Authentication Patterns in Next.js
How to implement session-based and token-based authentication in Next.js, protect routes with middleware, and handle auth in Server Components and Server Actions.
Next.js Quick Reference
A condensed cheat sheet of core Next.js App Router APIs, file conventions, rendering rules, and common commands for fast lookup.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics