DevSecOps

Next.js Build Errors: Complete Troubleshooting Guide

DeviDevs Team
7 min read
#nextjs#react#typescript#build-errors#troubleshooting

Next.js build errors can be cryptic. This guide covers all common build failures and their solutions for Next.js 14 and 15.

Error: Module Not Found

Symptom:

Module not found: Can't resolve 'some-package'
Error: Cannot find module '@/components/MyComponent'

Solution 1 - Install missing package:

npm install some-package

Solution 2 - Fix path alias:

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"]
    }
  }
}

Solution 3 - Check case sensitivity:

// ❌ Wrong (Windows may work, Linux fails)
import MyComponent from '@/Components/MyComponent';
 
// ✅ Correct (match actual file path)
import MyComponent from '@/components/MyComponent';

Error: Hydration Mismatch

Symptom:

Error: Hydration failed because the initial UI does not match what was rendered on the server
Warning: Expected server HTML to contain a matching <div> in <div>
Text content does not match server-rendered HTML

Cause 1 - Browser-only code in initial render:

// ❌ Causes hydration mismatch
export default function Component() {
  return <div>{window.innerWidth}</div>;  // window undefined on server
}
 
// ✅ Use useEffect for browser-only code
export default function Component() {
  const [width, setWidth] = useState(0);
 
  useEffect(() => {
    setWidth(window.innerWidth);
  }, []);
 
  return <div>{width || 'Loading...'}</div>;
}

Cause 2 - Date/time differences:

// ❌ Different on server vs client
<span>{new Date().toLocaleString()}</span>
 
// ✅ Suppress hydration warning or use useEffect
<span suppressHydrationWarning>{new Date().toLocaleString()}</span>
 
// ✅ Better: format on client only
const [time, setTime] = useState<string>();
useEffect(() => {
  setTime(new Date().toLocaleString());
}, []);

Cause 3 - Extension/browser modifications:

// Add suppressHydrationWarning to body for browser extensions
<body suppressHydrationWarning>
  {children}
</body>

Error: Dynamic Server Usage in Static Route

Symptom:

Error: Dynamic server usage: headers
Route /api/route couldn't be rendered statically because it used `headers`
Page "/page" is using dynamic server features

Solution 1 - Force dynamic rendering:

// app/page.tsx
export const dynamic = 'force-dynamic';
// or
export const revalidate = 0;

Solution 2 - Move dynamic code to client:

// ❌ Using headers in page component
import { headers } from 'next/headers';
export default function Page() {
  const headersList = headers();
  // ...
}
 
// ✅ Use in route handler or move to client
// app/api/route.ts
import { headers } from 'next/headers';
export async function GET() {
  const headersList = headers();
  // ...
}

Solution 3 - Use generateStaticParams:

// For dynamic routes that should be static
export async function generateStaticParams() {
  const posts = await getPosts();
  return posts.map((post) => ({
    slug: post.slug,
  }));
}

Error: Image Optimization Failed

Symptom:

Error: Invalid src prop on `next/image`
Error: Image Optimization using default loader is not compatible with `next export`
Error: upstream image response failed

Solution 1 - Configure remote images:

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
        pathname: '/images/**',
      },
      {
        protocol: 'https',
        hostname: '**.cloudinary.com',
      },
    ],
  },
};

Solution 2 - For static export:

// next.config.js
module.exports = {
  output: 'export',
  images: {
    unoptimized: true,  // Required for static export
  },
};

Solution 3 - Fix src path:

// ❌ Wrong - missing leading slash
<Image src="image.png" alt="..." width={100} height={100} />
 
// ✅ Correct - absolute path from public folder
<Image src="/image.png" alt="..." width={100} height={100} />
 
// ✅ Imported image (with dimensions)
import myImage from './image.png';
<Image src={myImage} alt="..." />

Error: TypeScript Build Errors

Symptom:

Type error: Property 'x' does not exist on type 'y'
Type error: Argument of type 'string' is not assignable to parameter of type 'number'

Solution 1 - Fix PageProps typing (Next.js 15):

// ❌ Old pattern (Next.js 14)
export default function Page({ params }: { params: { id: string } }) {}
 
// ✅ New pattern (Next.js 15) - params is a Promise
export default async function Page({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id } = await params;
  // ...
}

Solution 2 - Fix searchParams typing:

// Next.js 15 - searchParams is also a Promise
export default async function Page({
  searchParams,
}: {
  searchParams: Promise<{ query?: string }>;
}) {
  const { query } = await searchParams;
  // ...
}

Solution 3 - Ignore specific errors (temporary):

// @ts-ignore - TODO: Fix this type
const something = riskyOperation();
 
// @ts-expect-error - Expected to fail
const intentionalError = wrongType;

Error: "use client" Directive Issues

Symptom:

Error: useState only works in Client Components
Error: You're importing a component that needs useEffect
Attempted to call useRouter() from the Server

Solution 1 - Add "use client" directive:

// Must be at the very top of the file
'use client';
 
import { useState } from 'react';
 
export default function ClientComponent() {
  const [state, setState] = useState(false);
  // ...
}

Solution 2 - Split server/client components:

// ServerComponent.tsx (no directive needed)
import ClientPart from './ClientPart';
 
export default async function ServerComponent() {
  const data = await fetchData();  // Server-side fetch
  return <ClientPart initialData={data} />;
}
 
// ClientPart.tsx
'use client';
export default function ClientPart({ initialData }) {
  const [data, setData] = useState(initialData);
  // ...
}

Error: ESLint/Build Strict Mode

Symptom:

Build failed due to ESLint errors
Error: `next/image` should be imported from `next/image` not `next/legacy/image`

Solution 1 - Fix ESLint issues:

# Auto-fix what's possible
npm run lint -- --fix
 
# Or run ESLint directly
npx eslint --fix .

Solution 2 - Configure ESLint exceptions:

// .eslintrc.js
module.exports = {
  rules: {
    '@next/next/no-img-element': 'warn',  // Downgrade to warning
    'react-hooks/exhaustive-deps': 'warn',
  },
};

Solution 3 - Skip ESLint during build (not recommended):

// next.config.js
module.exports = {
  eslint: {
    ignoreDuringBuilds: true,  // Use only if necessary
  },
};

Error: Memory Issues During Build

Symptom:

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed
JavaScript heap out of memory

Solution 1 - Increase Node memory:

# Temporarily
NODE_OPTIONS="--max-old-space-size=8192" npm run build
 
# In package.json
{
  "scripts": {
    "build": "NODE_OPTIONS='--max-old-space-size=8192' next build"
  }
}

Solution 2 - Analyze bundle:

# Install bundle analyzer
npm install @next/bundle-analyzer
 
# next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});
 
module.exports = withBundleAnalyzer({
  // your config
});
 
# Run analysis
ANALYZE=true npm run build

Solution 3 - Reduce bundle size:

// Dynamic imports for large components
import dynamic from 'next/dynamic';
 
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <p>Loading...</p>,
  ssr: false,  // Don't include in server bundle
});

Error: API Route Issues

Symptom:

Error: API resolved without sending a response
TypeError: res.status is not a function

Solution - Use correct App Router patterns:

// app/api/route.ts (App Router)
import { NextResponse } from 'next/server';
 
export async function GET(request: Request) {
  return NextResponse.json({ message: 'Hello' });
}
 
export async function POST(request: Request) {
  const body = await request.json();
  return NextResponse.json({ received: body }, { status: 201 });
}

Quick Debug Commands

# Clear Next.js cache
rm -rf .next
 
# Clean install
rm -rf node_modules .next
npm install
 
# Build with verbose output
npm run build -- --debug
 
# Check for unused dependencies
npx depcheck
 
# Type check only
npx tsc --noEmit

Quick Reference: Common Fixes

| Error | Quick Fix | |-------|-----------| | Module not found | npm install package or fix import path | | Hydration mismatch | Use useEffect for browser-only code | | Dynamic server usage | Add export const dynamic = 'force-dynamic' | | Image optimization | Configure remotePatterns in config | | TypeScript params | Use Promise<{ param }> pattern | | "use client" needed | Add directive at top of file | | Memory issue | NODE_OPTIONS="--max-old-space-size=8192" |

Complex Next.js Applications?

Building production Next.js applications requires performance optimization expertise. Our team offers:

  • Performance audit and optimization
  • Migration to App Router
  • SSR/ISR strategy consulting
  • Deployment pipeline setup

Get Next.js expertise

Weekly AI Security & Automation Digest

Get the latest on AI Security, workflow automation, secure integrations, and custom platform development delivered weekly.

No spam. Unsubscribe anytime.