Problem Summary
Vercel builds your Next.js application in a Linux environment that differs from local development in three important ways: the file system is case-sensitive, environment variables must be explicitly configured in the Vercel dashboard, and serverless functions have a 50MB bundle size limit. Each of these causes a class of build failures that only appear on Vercel, not locally.
Cause 1: Missing or Misconfigured Environment Variables
Next.js has two categories of environment variables. Variables prefixed with NEXT_PUBLIC_ are inlined into the browser bundle at build time they must be set in the Vercel dashboard before the build runs. Variables without that prefix are only available at runtime on the server and do not need to be available during the build.
If your page or component accesses process.env.NEXT_PUBLIC_SOMETHING during static generation (getStaticProps or a Server Component that renders at build time), and that variable is not set in Vercel, the build will either error or silently produce pages with undefined values.
// ❌ NEXT_PUBLIC_ variable missing in Vercel dashboard
// Renders undefined in the deployed build
export default function Page() {
return <p>API: {process.env.NEXT_PUBLIC_API_URL}</p>;
}
// ❌ Server-only variable used in a component rendered during static build
// Will be undefined at build time even if set at runtime
export default async function Page() {
const data = await fetch(process.env.INTERNAL_API_URL + '/data'); // undefined
}Fix: Add variables in the Vercel dashboard
Go to your Vercel project > Settings > Environment Variables. Add each variable and select which environments it applies to (Production, Preview, Development). After adding or changing variables, trigger a new deployment environment variables are baked in at build time and do not apply retroactively.
You can import a .env file directly in the Vercel dashboard using the bulk import option. This avoids manually entering each variable and reduces the chance of typos.
Cause 2: Module Not Found (Case Sensitivity)
Windows and macOS file systems are case-insensitive by default. You can import from '@/components/Button' even if the file is named 'button.tsx' and it will work locally. Vercel runs on Linux, where the file system is case-sensitive. The same import fails in production with 'Module not found: Can't resolve @/components/Button'.
// File on disk: src/components/button.tsx
// ❌ Works locally (Windows/macOS), fails on Vercel (Linux)
import Button from '@/components/Button';
// ✓ Matches the actual filename exactly
import Button from '@/components/button';Find all mismatched import paths
grep -r "from '@/" src/ | grep -i "components" | sortCompare the imported names against the actual file names on disk. Fix any casing mismatch in the import statement or rename the file to match the convention you use in imports. Committing both changes together avoids a broken intermediate state.
Cause 3: Serverless Function Size Limit (50MB)
Vercel serverless functions have a maximum bundle size of 50MB. If your application imports a large library PDF generation, image processing, a machine learning model, a large locale file directly into a page or API route, the function bundle can exceed this limit and the deployment fails.
# Vercel build error:
# Error: Serverless Function "api/generate-pdf" is 68.4 MB which exceeds
# the maximum size of 50 MBIdentify what is inflating the bundle
ANALYZE=true npm run buildInstall @next/bundle-analyzer and add it to next.config.js to get a visual breakdown of what is in each bundle. Look for unexpectedly large dependencies in the server-side bundle.
Fix: Use dynamic imports for large dependencies
// ❌ Static import bundles the library into the function at build time
import PDFDocument from 'pdfkit';
export async function POST(req: Request) {
const doc = new PDFDocument();
// ...
}
// ✓ Dynamic import loads the library only when the function is called
export async function POST(req: Request) {
const { default: PDFDocument } = await import('pdfkit');
const doc = new PDFDocument();
// ...
}Cause 4: Prisma Client Not Generated Before Build
Prisma generates a type-safe client from your schema at build time. If prisma generate has not run before next build, the import from '@prisma/client' will fail with 'Module not found' or throw a runtime error about the Prisma client not being initialised.
{
"scripts": {
"postinstall": "prisma generate",
"build": "next build"
}
}
// The postinstall script runs automatically after npm install on Vercel
// This ensures prisma generate always runs before next buildIf your schema is in a non-default location, pass the schema path explicitly: prisma generate --schema=./path/to/schema.prisma
Cause 5: Edge Runtime Using Node.js APIs
If a file exports export const runtime = 'edge', Vercel runs it in the Edge Runtime a lightweight V8-based environment that does not include Node.js built-in modules. Importing fs, path, crypto (Node version), net, or any native module in an Edge function causes an immediate build error.
// ❌ fs is not available in the Edge Runtime
export const runtime = 'edge';
import fs from 'fs';
export async function GET() {
const data = fs.readFileSync('./data.json', 'utf8'); // Build error
return new Response(data);
}
// ✓ Option 1: Remove the edge runtime declaration to use Node.js runtime
// (delete the line below, or set it explicitly)
export const runtime = 'nodejs';
// ✓ Option 2: Use fetch instead of fs for remote data
export const runtime = 'edge';
export async function GET() {
const res = await fetch('https://yourapi.com/data');
return new Response(await res.text());
}General Diagnosis Steps
- 1Run npm run build locally first if it fails locally, fix it locally before looking at Vercel
- 2Read the full Vercel build log the first error message is the real cause; later errors are often cascading failures
- 3Check environment variables open the failed deployment in Vercel, go to Settings > Environment Variables and verify every variable the build needs is present
- 4Verify file name casing run git ls-files | grep -i components and compare with your import statements
- 5Check the Vercel function size look for 'exceeded maximum size' in the build log and use bundle analysis to identify large dependencies
- 6Check for prisma generate if using Prisma, ensure postinstall runs prisma generate in package.json
- 7Check runtime declarations search for export const runtime = 'edge' and verify those files do not import Node.js built-ins
Vercel caches dependencies between builds. If you suspect a stale cache is causing the failure, open the deployment in the Vercel dashboard, click the three-dot menu, and select 'Redeploy' with 'Use existing Build Cache' unchecked.