Skip to main content
All guides
Debugging

Debugging Vercel build fails: the fastest path to green

Every red X in the Vercel dashboard is one of about five underlying problems. Here's how to spot each one from the log and fix it in under 10 minutes.

Last updated July 18, 2026

Read the log, not the UI

The Vercel dashboard summarizes with a red X and a two-line reason. The actual failure is always in the deploy log, and always at the FIRST non-zero exit — later errors are usually cascading noise from the first one. Open the failed deployment, click Build Logs, and search the log for 'error' with Cmd/Ctrl-F. Stop at the earliest match. Ninety percent of the time that first hit is the entire story. The other ten percent, the first error is a misleading warning and the true cause is a stack trace three lines down; read the surrounding context before you commit to a fix.

1. Node version mismatch

Symptom: 'Unexpected token' on syntax your local Node supports, or a package error like 'Package X requires Node >=20'. Fix: set the Node version explicitly in Project Settings → Node.js Version, and mirror it in package.json under engines.node. Do not rely on Vercel's default — it drifts over time as Vercel upgrades their build image, and a working build can silently break after a platform update. Once pinned, review the pin every quarter; a stale Node version eventually stops receiving security patches and Vercel will force an upgrade.

2. Missing environment variable

Symptom: 'process.env.X is undefined' during build, often inside getStaticProps, generateStaticParams, or a top-level module init. Fix: add the variable in Project Settings → Environment Variables and re-deploy. Preview, Production, and Development are separate scopes — a var set only for Production will not reach a PR preview build. If a variable is truly required for the site to render, add a build-time guard that throws with a clear message, so the failure is loud instead of a mystery undefined downstream.

3. Out-of-memory during build

Symptom: 'JavaScript heap out of memory' or the build dies mid-log with no clear cause and an exit code 137 (SIGKILL). Fix: bump the Node memory ceiling with NODE_OPTIONS='--max-old-space-size=4096' as a build-scoped env var. On free tier this can still hit the platform ceiling — trim your dependency graph, split routes, or upgrade to Pro. Very large Next.js apps sometimes benefit from setting experimental.workerThreads: false to reduce peak memory, at the cost of slower builds.

4. Wrong output directory

Symptom: 'No Output Directory named `dist` found' or `.next` for the wrong framework. Fix: match Project Settings → Build & Development → Output Directory to what your framework actually produces. Vite is dist. Next.js is .next. Astro is dist. SvelteKit varies by adapter. Remix varies by adapter. If you recently switched frameworks or upgraded a major version, this is almost always the cause. Set the framework preset first and let Vercel infer the defaults before overriding anything.

5. Monorepo path error

Symptom: 'Cannot find package.json' or a build that runs the wrong workspace. Fix: set Root Directory in Project Settings to the correct workspace path (e.g. apps/web). Also verify the build command uses the workspace-scoped variant — pnpm --filter web build, turbo run build --filter=web, nx build web. Vercel will happily run `pnpm build` from the monorepo root and then fail with a confusing error because there is no build script at the root. Explicit filter flags fix this.

Bonus failure modes worth knowing

  • Case-sensitive filenames — Linux enforces case, macOS does not. `import Header from './header'` succeeds locally and fails on Vercel if the file is Header.tsx.
  • Peer dependency conflicts — pnpm and npm handle these differently; pinning package-manager version in package.json prevents drift.
  • Missing native binaries — sharp, esbuild, and @swc/core ship platform-specific binaries; running with --frozen-lockfile on Vercel can miss a binary if your lockfile was generated on a different OS.
  • Environment-specific feature flags — a flag enabled only in Production can fail an SSR path that Preview never exercised.

Quick triage checklist

  • Open the deploy log and Cmd/Ctrl-F for 'error'. Stop at the first hit.
  • Compare Node version in the log with your local (node -v).
  • Confirm every env var referenced in the failing step exists for that environment.
  • If the log ends abruptly with no error, assume OOM until proven otherwise.
  • If everything else looks fine, redeploy without cache — sometimes the build cache is corrupt.
  • If a recent Vercel platform change coincides with the break, check the Vercel status page and their changelog.

What to do when nothing on the list applies

About one in twenty build fails don't fit any of the standard buckets. When you're stuck, do three things: reproduce locally with the exact Node version and env vars from Vercel, run the build with `vercel build --debug` to get the same output Vercel sees, and diff the last successful commit against the failing one. Nine out of ten mystery fails come down to a dependency bump, a lockfile change, or a subtle path rewrite that only bites in a clean build environment. If the diff is truly empty, redeploy without cache — very rarely, a corrupt build cache is the entire story.

FAQ

Why does my build succeed locally but fail on Vercel?
Almost always one of three things: a Node version mismatch (local is newer or older than Vercel's build image), a missing environment variable that only shows up in a fresh clone, or a case-sensitive filename that Linux enforces and macOS does not. Check the Node version in the deploy log first, then env vars for the specific environment (Preview vs Production), then grep your imports against the actual filenames on disk with `ls` — not the editor's fuzzy match.
How do I retry a build without pushing a new commit?
Open the failed deployment in the Vercel dashboard and click Redeploy. Uncheck 'Use existing Build Cache' if you suspect a corrupt cache — this is a real thing that happens once in a while, especially after dependency upgrades or a switch of package manager. You can also trigger a redeploy from the CLI with `vercel --prod` from the project directory, which is useful when the dashboard is slow.
What's the memory ceiling on a Vercel build?
The build container's Node process defaults to about 2GB. Bump it with NODE_OPTIONS='--max-old-space-size=4096' as a build-scoped env var; the platform hard-caps around 8GB on Pro and higher on Enterprise. If a straightforward memory bump doesn't fix an OOM, the culprit is usually a build tool holding onto AST for too long — try disabling source maps in production, splitting routes into more chunks, or upgrading to a newer bundler version.
Do preview and production share environment variables?
No — Preview, Production, and Development are separate scopes. A variable set only for Production will be undefined in a PR preview build, and vice versa. The Vercel dashboard lets you set the same value across scopes with a single click, which is what you usually want for public config; secrets like DB URLs and API keys should differ per environment. When adding a new var, always confirm the scope checkboxes before saving.
Why does my build cache keep going stale?
The build cache is keyed by lockfile hash, framework version, and a rolling internal version. When any of those change, Vercel invalidates the cache and rebuilds from scratch. Frequent invalidations usually mean a moving dependency (a package with `latest` or a `^` range that keeps changing), a lockfile that regenerates on every commit, or a CI process that regenerates node_modules ordering. Pin your package manager version in package.json and use `--frozen-lockfile` to stabilize the cache.
How do I debug a build that hangs?
Vercel kills hung builds after roughly 45 minutes on Pro. If you're regularly hitting that ceiling, run the build locally with a wall-clock timer to find the slow step. Common culprits: a postinstall script that fetches remote resources without a timeout, an infinite loop in a code generator, or a native binary trying to compile on a build image that doesn't have the toolchain. Enable `--verbose` on your build command to get per-step timing.
Can I SSH into the build container?
No — Vercel does not expose the build environment interactively. The closest equivalent is `vercel build --debug` locally, which uses the same builder logic as the cloud. For inspecting the build image itself, Vercel publishes the base image versions in their docs, and you can reproduce most issues in a matching Docker container. When that still isn't enough, add `console.log` liberally around the failing step and re-deploy; noisy logs are cheap on Vercel.
Should I use vercel.json or Project Settings?
Prefer Project Settings for anything you would want to change through a UI (env vars, build commands, output directory). Use vercel.json for anything you want tracked in version control alongside code (headers, redirects, rewrites, cron schedules, function region hints). The two layers merge at deploy time, with vercel.json winning for keys it defines. Keeping most settings in the UI avoids merge conflicts and keeps secrets out of source control.

Related on this site

Keep reading