next build) fall into 6 main
categories: (1) TypeScript/ESLint errors treated as fatal, (2) module resolution failures
(Module not found), (3) server/client boundary violations (using window in
Server Components), (4) data fetching errors in
getStaticProps/getStaticPaths/generateStaticParams, (5)
out-of-memory crashes on large apps, (6) Turbopack compatibility issues (Next.js 16+ default bundler).
npx next build --debug for verbose output +
NEXT_DEBUG_LOGGING=1 for detailed build traces. Use
npx next build --webpack to fall back from Turbopack.
next dev but fails in
next build — dev mode is lenient, production build is strict. Next.js 16 uses Turbopack for
both dev and build by default, so custom webpack configs are silently ignored unless you pass
--webpack. [src3]
next build. Custom webpack configurations in
next.config.js are ignored unless you explicitly pass --webpack. Check
turbopack.rules for loader replacements. [src3, src7]
typescript: { ignoreBuildErrors: true } and
eslint: { ignoreDuringBuilds: true } in production — this hides real bugs and accumulates
tech debt silently. [src5]
ReactDOM.render(). All projects must use
createRoot(). Failing to migrate causes build-time errors. [src4]
NEXT_PUBLIC_ prefix are server-only. Using them in client
components causes undefined at build time, crashing pre-rendering. [src1, src2]params and searchParams to return Promises in dynamic
routes. Using them synchronously causes type errors that block the build. [src4]| # | Error Category | Signature | Likelihood | Fix |
|---|---|---|---|---|
| 1 | TypeScript type errors | Type error: ... is not assignable to type |
~22% of cases | Fix types or set typescript: { ignoreBuildErrors: true } in
next.config.js (not recommended) [src5]
|
| 2 | Module not found | Module not found: Can't resolve '...' |
~18% of cases | Install missing package, fix import path, check case sensitivity on Linux [src1, src6] |
| 3 | Async params type error (Next.js 15+) | Type 'Promise<any>' is not assignable |
~12% of cases | Await params and searchParams in dynamic routes — they return
Promises now [src4] |
| 4 | Server/client boundary | document is not defined, window is not defined |
~10% of cases | Add "use client" directive, or move code to useEffect [src1, src6] |
| 5 | ESLint errors | ESLint: ... (error) blocking build |
~8% of cases | Fix lint errors or set eslint: { ignoreDuringBuilds: true } [src2] |
| 6 | Static generation failure | Error occurred prerendering page "/" |
~8% of cases | Fix data fetching in getStaticProps/generateStaticParams, check
API availability at build time [src1, src6] |
| 7 | Turbopack webpack config ignored | Build succeeds but missing loaders/transforms | ~6% of cases | Migrate webpack config to turbopack.rules or use --webpack flag
[src3, src7] |
| 8 | Missing getStaticPaths |
getStaticPaths is required for dynamic SSG pages |
~4% of cases | Add getStaticPaths or switch to getServerSideProps /
force-dynamic [src1]
|
| 9 | Image optimization | Invalid src prop ... hostname not configured |
~4% of cases | Add hostname to images.remotePatterns in next.config.js [src2] |
| 10 | Heap out of memory | FATAL ERROR: Reached heap limit Allocation failed |
~3% of cases | Increase memory: NODE_OPTIONS='--max-old-space-size=4096' [src8] |
| 11 | Environment variable missing | Runtime crash from undefined env var |
~3% of cases | Add env vars to build environment; prefix with NEXT_PUBLIC_ for client [src1, src2] |
| 12 | Case sensitivity (Linux CI) | Module not found only in CI, works locally |
~2% of cases | Match exact file/folder casing in all imports [src5, src6] |
START
├── Using Next.js 16 with custom webpack config?
│ ├── YES → Migrate to turbopack.rules or use --webpack flag [src3, src7]
│ └── NO ↓
├── Error contains "Type error" or "TS"?
│ ├── YES → Is it "Promise<any> is not assignable"?
│ │ ├── YES → Await params/searchParams (Next.js 15+ async API change) [src4]
│ │ └── NO → Fix the type, or check tsconfig.json strict settings [src5]
│ └── NO ↓
├── Error contains "Module not found"?
│ ├── YES → Check: is the package installed? Is the import path correct?
│ │ ├── Works locally, fails in CI → Case sensitivity issue (Linux is case-sensitive) [src6]
│ │ ├── Using path alias (@/) → Verify tsconfig.json paths + next.config.js [src2]
│ │ └── Using Node.js API (fs, path) in client code → Move to server-only code [src1]
│ └── NO ↓
├── Error contains "window is not defined" or "document is not defined"?
│ ├── YES → Server/client boundary violation
│ │ ├── App Router → Add "use client" directive to component [src1]
│ │ └── Pages Router → Wrap in useEffect or use next/dynamic with ssr: false [src6]
│ └── NO ↓
├── Error contains "prerendering" or "getStaticPaths"?
│ ├── YES → Static generation error
│ │ ├── API not available at build time → Use fallback: true or ISR [src1]
│ │ ├── Dynamic route missing getStaticPaths → Add it, or use getServerSideProps [src1]
│ │ └── Data fetching throws → Add try/catch, check env vars for DB/API URLs [src6]
│ └── NO ↓
├── Error contains "ESLint"?
│ ├── YES → Fix lint errors or add eslint: { ignoreDuringBuilds: true } [src2]
│ └── NO ↓
├── Error contains "heap" or "FATAL ERROR" or "out of memory"?
│ ├── YES → NODE_OPTIONS='--max-old-space-size=4096' next build [src8]
│ └── NO ↓
├── Error contains "Invalid src prop" (images)?
│ ├── YES → Add hostname to images.remotePatterns in next.config.js [src2]
│ └── NO ↓
├── Error contains "Mismatching @next/swc version"?
│ ├── YES → Delete node_modules and package-lock.json, run npm install [src1]
│ └── NO ↓
└── DEFAULT → Run next build with NEXT_DEBUG_LOGGING=1, check full stack trace
Always reproduce the error locally before debugging. Dev mode (next dev) is lenient — production
build (next build) enforces strict checks. [src6]
# Clean build — remove cached artifacts first
rm -rf .next node_modules/.cache
npx next build
Verify: Error should appear in terminal output with a file path and line number.
Get more detail on what's happening during the build. [src1]
# Verbose debug output
NEXT_DEBUG_LOGGING=1 npx next build --debug
# On Windows PowerShell
$env:NEXT_DEBUG_LOGGING=1; npx next build --debug
Verify: Build output now includes detailed webpack/turbopack compilation info and page generation steps.
Next.js 16 made Turbopack the default bundler for both dev and build. If you have custom webpack configuration, it will be silently ignored. [src3, src7]
# If build fails with Turbopack, test with webpack fallback
npx next build --webpack
/** @type {import('next').NextConfig} */
const nextConfig = {
// Turbopack-specific configuration (replaces webpack config)
turbopack: {
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
resolveAlias: {
'old-package': 'new-package',
},
},
};
module.exports = nextConfig;
Verify: npx next build completes without Turbopack errors, or
npx next build --webpack works as fallback.
Next.js 15 changed params and searchParams to async APIs that return Promises.
Using them synchronously causes TypeScript build errors. [src4]
// ❌ WRONG (Next.js 14 style — fails in Next.js 15+)
export default function Page({ params }: { params: { id: string } }) {
return <div>{params.id}</div>;
}
// ✅ CORRECT (Next.js 15+ style — await the Promise)
export default async function Page({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
return <div>{id}</div>;
}
Verify: npx next build completes without
Promise<any> is not assignable errors.
TypeScript errors are treated as fatal by default in next build. Fix each error, or as a
temporary escape hatch, disable enforcement. [src5]
// next.config.js — TEMPORARY escape hatch (not recommended for production)
/** @type {import('next').NextConfig} */
const nextConfig = {
typescript: {
ignoreBuildErrors: true, // Only use to unblock deploy while fixing types
},
};
module.exports = nextConfig;
Better approach — fix the actual type errors:
// ❌ WRONG — implicit any causes build error in strict mode
function fetchData(id) { /* ... */ }
// ✅ CORRECT — explicit types
function fetchData(id: string): Promise<Data> { /* ... */ }
Verify: npx next build completes without TypeScript errors.
Check the exact error message for the module path, then trace the cause. [src1, src6]
# Check if the package is installed
npm ls <package-name>
# If missing, install it
npm install <package-name>
# If using path aliases, verify tsconfig.json
cat tsconfig.json | grep -A5 '"paths"'
For case sensitivity issues (works on macOS/Windows, fails on Linux CI):
# Find case mismatches in imports
grep -rn "from ['\"]" --include="*.tsx" --include="*.ts" src/ | sort | head -50
# Compare with actual file names
find src/ -name "*.tsx" -o -name "*.ts" | sort
Verify: npx next build resolves all modules successfully.
In the App Router, all components are Server Components by default. Browser APIs (window,
document, localStorage) are unavailable on the server. [src1, src6]
// ❌ WRONG — window is not defined on the server
// app/components/Navbar.jsx (Server Component by default)
export default function Navbar() {
const isMobile = window.innerWidth < 768; // CRASH
return <nav>{isMobile ? 'Mobile' : 'Desktop'}</nav>;
}
// ✅ CORRECT — add 'use client' and use useEffect
// app/components/Navbar.jsx
'use client';
import { useState, useEffect } from 'react';
export default function Navbar() {
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
setIsMobile(window.innerWidth < 768);
}, []);
return <nav>{isMobile ? 'Mobile' : 'Desktop'}</nav>;
}
Verify: npx next build completes without window is not defined
errors.
When next build pre-renders pages, it runs your data fetching code at build time. APIs or
databases must be available. [src1, src6]
// Pages Router — getStaticPaths required for dynamic [id] routes
export async function getStaticPaths() {
try {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
paths: posts.map((post) => ({ params: { id: String(post.id) } })),
fallback: 'blocking', // Generate unknown paths on-demand
};
} catch (error) {
return { paths: [], fallback: 'blocking' };
}
}
// App Router — generateStaticParams equivalent
export async function generateStaticParams() {
try {
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
return posts.map((post) => ({ id: String(post.id) }));
} catch {
return []; // Empty = generate all on-demand [src1]
}
}
Verify: npx next build completes static generation without API errors.
Large apps with many pages or heavy dependencies can exhaust the default Node.js heap. [src8]
# Increase Node.js memory limit for build
NODE_OPTIONS='--max-old-space-size=4096' npx next build
# Analyze bundle to find large dependencies
npm install --save-dev @next/bundle-analyzer
Verify: Build completes without FATAL ERROR. Check bundle report for oversized chunks.
// Input: Component using browser APIs that fails during next build
// Output: Properly split server + client components
// app/layout.tsx — Server Component (default)
import ClientNav from './components/ClientNav';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<ClientNav /> {/* Client component handles browser APIs */}
<main>{children}</main>
</body>
</html>
);
}
// app/components/ClientNav.tsx — Client Component
'use client';
import { useState, useEffect } from 'react';
export default function ClientNav() {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const handleScroll = () => setScrolled(window.scrollY > 50);
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return (
<nav className={scrolled ? 'nav-scrolled' : 'nav-top'}>
<a href="/">Home</a>
</nav>
);
}
// Input: Next.js 14 dynamic route page with sync params
// Output: Next.js 15+ compatible page with async params [src4]
type Props = {
params: Promise<{ slug: string }>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
};
export default async function BlogPost({ params, searchParams }: Props) {
const { slug } = await params;
const { page } = await searchParams;
const post = await getPost(slug);
return <article><h1>{post.title}</h1></article>;
}
// Input: next.config.js with custom webpack config (breaks in Next.js 16)
// Output: Turbopack-compatible configuration [src3, src7]
/** @type {import('next').NextConfig} */
const nextConfig = {
turbopack: {
rules: {
'*.svg': { loaders: ['@svgr/webpack'], as: '*.js' },
},
resolveAlias: { '@components': './src/components' },
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
},
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'cdn.example.com' },
],
},
output: 'standalone',
};
module.exports = nextConfig;
// Input: next.config.js causing or preventing build errors
// Output: Properly configured next.config.js with error handling
/** @type {import('next').NextConfig} */
const nextConfig = {
// Image optimization: allow external image domains
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'cdn.example.com' },
{ protocol: 'https', hostname: 'images.unsplash.com' },
],
},
// Webpack customization (e.g., handle Node.js modules in client code)
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.fallback = {
...config.resolve.fallback,
fs: false,
net: false,
tls: false,
};
}
return config;
},
// Redirect trailing slashes
trailingSlash: false,
// Output: standalone for Docker deployments
output: 'standalone',
};
module.exports = nextConfig;
#!/bin/bash
# Input: CI/CD build script for Next.js
# Output: Robust build with error handling, memory management
set -euo pipefail
echo "=== Next.js Production Build ==="
echo "Node: $(node -v)"
echo "npm: $(npm -v)"
# Step 1: Clean previous build artifacts
rm -rf .next
# Step 2: Install dependencies
npm ci
# Step 3: Validate environment variables
REQUIRED_VARS=("DATABASE_URL" "NEXT_PUBLIC_API_URL" "API_SECRET")
for var in "${REQUIRED_VARS[@]}"; do
if [ -z "${!var:-}" ]; then
echo "ERROR: Required env var $var is not set"
exit 1
fi
done
# Step 4: Build with increased memory
NODE_OPTIONS='--max-old-space-size=4096' npx next build
echo "Build completed successfully"
// ❌ BAD — hides real type bugs, tech debt builds up [src5]
// next.config.js
module.exports = {
typescript: { ignoreBuildErrors: true },
eslint: { ignoreDuringBuilds: true },
};
// ✅ GOOD — fix actual errors, maintain type safety [src5]
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"forceConsistentCasingInFileNames": true // catches case issues
}
}
// Then fix all reported type errors one by one
// ❌ BAD — fs doesn't exist in the browser [src1, src6]
// app/components/FileViewer.tsx
'use client';
import fs from 'fs';
export default function FileViewer() {
const content = fs.readFileSync('./data.json', 'utf-8');
return <pre>{content}</pre>;
}
// ✅ GOOD — read files on the server, pass data as props [src1]
// app/page.tsx (Server Component — no 'use client')
import fs from 'fs';
import path from 'path';
export default function Page() {
const filePath = path.join(process.cwd(), 'data.json');
const content = fs.readFileSync(filePath, 'utf-8');
const data = JSON.parse(content);
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
// ❌ BAD — build fails if API is down or returns incomplete data [src1]
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
paths: posts.map(p => ({ params: { id: p.id } })),
fallback: false, // No fallback = 404 for any path not in list
};
}
// ✅ GOOD — graceful fallback, error handling [src1, src6]
export async function getStaticPaths() {
try {
const res = await fetch('https://api.example.com/posts');
if (!res.ok) throw new Error(`API returned ${res.status}`);
const posts = await res.json();
return {
paths: posts.slice(0, 50).map(p => ({ params: { id: String(p.id) } })),
fallback: 'blocking',
};
} catch (error) {
console.error('getStaticPaths failed:', error);
return { paths: [], fallback: 'blocking' };
}
}
// ❌ BAD — params is now a Promise in Next.js 15+, causes type error [src4]
export default function Page({ params }: { params: { id: string } }) {
return <div>{params.id}</div>;
}
// ✅ GOOD — properly handle async params [src4]
export default async function Page({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
return <div>{id}</div>;
}
next dev skips TypeScript type checking, doesn't
pre-render pages, and is lenient with imports. Always test with next build before
deploying. [src6]MyComponent.tsx === mycomponent.tsx). Linux (CI/CD servers) is
case-sensitive. Fix: enable forceConsistentCasingInFileNames: true in
tsconfig.json. [src5, src6]
NEXT_PUBLIC_ prefix forgotten: Environment variables without
NEXT_PUBLIC_ prefix are not available in client-side code. The value will be
undefined at runtime, potentially crashing the build during pre-rendering. [src1, src2]
.next cache: Cached build artifacts can cause phantom errors that
don't match your current code. Fix: rm -rf .next before building. [src6]devDependencies wrongly used: If a package needed at build-time is in
devDependencies and your CI uses npm install --production, it won't be
available. Fix: move it to dependencies or ensure CI installs all deps. [src6]
next/dynamic(() => import('./path')) —
the path must be a static string literal. Variables or template literals in import paths cause webpack
to fail. [src1]next.config.js are silently ignored. Builds may succeed but miss
transforms. Fix: migrate to turbopack.rules or use --webpack flag. [src3, src7]@next/swc version warnings after
partial upgrades. Fix: delete node_modules and package-lock.json, then
npm install. [src1]
# Clean build (remove cached artifacts)
rm -rf .next node_modules/.cache
# Build with verbose logging
NEXT_DEBUG_LOGGING=1 npx next build --debug 2>&1 | tee build.log
# Build with increased memory (4GB)
NODE_OPTIONS='--max-old-space-size=4096' npx next build
# Build with webpack fallback (Next.js 16+ when Turbopack fails)
npx next build --webpack
# Check Node.js version compatibility
node -v # Must be >= 18.18.0 for Next.js 15+, >= 20.x for Next.js 16
# Check for TypeScript errors without building
npx tsc --noEmit
# Check for ESLint errors without building
npx next lint
# Analyze bundle size
ANALYZE=true npx next build
# Verify environment variables are set
env | grep NEXT_PUBLIC_ | sort
# Find case-sensitive import mismatches
find src/ app/ -type f \( -name "*.tsx" -o -name "*.ts" \) | sort > /tmp/files.txt
grep -roh "from ['\"][^'\"]*['\"]" src/ app/ --include="*.ts" --include="*.tsx" | sort > /tmp/imports.txt
# Check for SWC version mismatch
npm ls @next/swc-linux-x64-gnu @next/swc-darwin-arm64 2>/dev/null
# Run Next.js upgrade codemod (for version migrations)
npx @next/codemod@latest upgrade
| Version | Build Behavior | Key Changes |
|---|---|---|
| Next.js 16 (React 19) | Current | Turbopack default for dev + build, --webpack fallback, filesystem caching,
2-5x faster builds [src3, src7] |
| Next.js 15 (React 19) | Supported | Async request APIs (params, searchParams return Promises),
caching uncached by default, stricter build validation [src4] |
| Next.js 14 (React 18) | Supported | App Router stable, Server Actions stable, next/image improvements [src2] |
| Next.js 13 (React 18) | Supported | App Router introduced (beta), app/ directory, React Server Components [src1] |
| Next.js 12 (React 17-18) | Legacy | Pages Router only, SWC compiler default, middleware [src2] |
| Next.js 11 and below | EOL | Babel-based compilation, older React versions |
| Use When | Don't Use When | Use Instead |
|---|---|---|
next build exits with non-zero code |
App runs fine but is slow | Performance optimization guide |
| Build passes locally but fails in CI/CD | Runtime error after successful build | React error boundary / debugging guide |
| Error during static page generation | Hydration mismatch warning (app still works) | Hydration mismatch guide |
| TypeScript or ESLint blocking build | Styling or CSS issues at runtime | CSS debugging guide |
| Turbopack build fails in Next.js 16 | Turbopack dev server slow (not a build error) | Turbopack performance docs |
next dev and
next build. Custom webpack configurations are silently ignored. Use --webpack
to opt out, or migrate to turbopack.rules. [src3]
params and searchParams to async APIs returning Promises.
This is a breaking change that causes TypeScript build errors. Run
npx @next/codemod@latest upgrade to automate the migration. [src4]
app/) and Pages Router (pages/) can coexist, but have
different build behaviors. app/ treats all components as Server Components by default;
pages/ does not.
typescript: { ignoreBuildErrors: true } is a dangerous escape hatch — it hides real bugs.
Use it only as a temporary measure while fixing types incrementally. [src5]getStaticProps or Server Components must be available at
build time, not just runtime. Verify they're set in your CI/CD build environment. [src1]turbopack.rules configuration. [src7]