The Build Pipeline: From Source to Bundle
The Build Pipeline: From Source to Bundle
What Actually Happens When You Run npm run build
Most developers run npm run dev, build features, then hand it to Vercel and hope for the best. Understanding what the build step actually does makes you 10x better at debugging production issues.
---
The Full Pipeline
Source code (.tsx, .ts, .css)
↓
TypeScript compiler (tsc) — type checks, strips types
↓
Next.js compiler (SWC) — transforms JSX, handles imports
↓
Bundler (webpack/turbopack) — resolves deps, code splits
↓
Minifier — removes whitespace, shortens variable names
↓
Output: .next/ directory
↓
Vercel deployment (CDN + edge network)---
Reading Build Output
Run npm run build and read what it tells you:
Route (app) Size First Load JS
┌ ○ / 4.2 kB 112 kB
├ ○ /about 1.1 kB 109 kB
├ ● /courses/[id] 8.7 kB 147 kB
└ ƒ /api/tts 0 B 0 B
○ Static ● Dynamic ƒ Serverless Function- ○ Static — pre-rendered HTML at build time, served from CDN, fastest possible
- ● Dynamic — rendered on each request (uses
fetchwith no cache, cookies, or headers) - ƒ Serverless Function — your API routes, run on-demand
First Load JS is the critical number. Under 130 kB is good. Over 300 kB needs investigation.
---
Environment Variables: Build vs Runtime
This is the #1 source of production bugs for new developers.
# .env.local (never commit this)
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co # ← bundled into client JS
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhb... # ← bundled into client JS
SUPABASE_SERVICE_KEY=eyJhb... # ← SERVER ONLY, never exposed
OPENAI_API_KEY=sk-... # ← SERVER ONLY, never exposedRule: NEXT_PUBLIC_ = visible to everyone in the browser. Never put secrets there.
---
Vercel's Build System
When you push to GitHub, Vercel:
- Clones your repo
- Runs
npm install(uses package-lock.json for exact versions) - Runs your build command (default:
npm run build) - Deploys
.next/to its global CDN - Spins up serverless functions for API routes
Critical: Vercel builds in a clean environment. It has no access to your .env.local. Environment variables must be added in the Vercel dashboard under Settings → Environment Variables.
---
Common Build Failures and Fixes
TypeScript errors blocking build:
# Check locally first — never push blindly
npx tsc --noEmitMissing environment variables:
Error: NEXT_PUBLIC_SUPABASE_URL is not definedAdd the variable to Vercel dashboard, then redeploy.
Module not found:
npm install # install missing dep
# Commit package.json + package-lock.jsonBuild succeeds locally, fails on Vercel:
- You have a file import that works on macOS (case-insensitive) but fails on Linux (case-sensitive):
import Button from './button'→ should be'./Button' - You're using a Node.js API in a component that runs at the edge
---
The next.config.js Production Checklist
const nextConfig = {
// Images from external domains must be explicitly allowed
images: {
remotePatterns: [{ hostname: 'your-supabase-project.supabase.co' }],
},
// Redirects — handled at CDN level, zero latency
async redirects() {
return [
{ source: '/old-path', destination: '/new-path', permanent: true },
]
},
}