Skip to content
Book a call

4 min readEngineering

Your Next.js app works locally and fails in production: the usual causes

Why a Next.js app that runs fine with npm run dev breaks on Vercel, Docker, AWS or Cloudflare, and how to find which cause it is in minutes.

A Next.js app that works with npm run dev and breaks once deployed is almost always one of a few things: environment variables that aren't set on the host or were baked in at build time, the production build being stricter than dev, a page that became static when you expected it to be live, or code that assumes a long-running server on a platform that doesn't have one. Run npm run build && npm start on your machine first: if it breaks there too, the problem is the build, not the host.

1. Environment variables

  • Missing on the host.env.local isn't deployed. Every variable has to be added in Vercel, your Docker run command or your cloud's settings.
  • NEXT_PUBLIC_ is baked in at build timeVariables with that prefix are written into the JavaScript when you build. Changing them on the host later does nothing until you rebuild, and in Docker they must be present when the image is built, not just when it runs.
  • Secrets in the browserA secret key given the NEXT_PUBLIC_ prefix to make an error go away is now public. Move that call to the server instead.

2. The production build is stricter than dev

  • next build fails on type errors that dev only warns about.
  • File names are case-sensitive on Linux servers: import Header from "./header" works on a Mac and fails on the host if the file is Header.tsx.
  • A different Node version on the host. Pin it in package.json engines or your Dockerfile.
  • Code that touches window or localStorage while the page is rendered on the server.

3. A page went static, or stayed cached

Pages without dynamic data are rendered once at build time. A page that showed fresh data in dev can show build-day data in production. Look at the build output: pages marked as static were frozen. Reading cookies or headers, export const dynamic = "force-dynamic", or revalidate tells Next.js how fresh a page should be.

4. Serverless and edge limits

  • Each request can open a new database connection. Use your database's pooled connection string (Supabase's pooler, for example) or you'll run out of connections under load.
  • Functions time out. Long jobs belong in a queue or background task, not in a route handler.
  • Edge runtime and Cloudflare Workers don't have every Node API. Libraries that need fs or native modules fail there.
  • Files written to disk at runtime disappear between requests.

5. URLs and sign-in callbacks

Hard-coded http://localhost:3000 links, OAuth redirect URLs that only list localhost, Supabase Auth's site URL left on localhost, and images from domains missing in images.remotePatterns. Sign-in that works locally and loops in production is nearly always a callback URL.

6. Docker and AWS specifics

Set output: "standalone" in next.config and copy .next/standalone, .next/static and public into the image; a missing static folder gives you a page with no styles. Listen on 0.0.0.0, not localhost, inside the container, and pass the port your platform expects.

How to find which one it is

  1. Build locally in production modenpm run build && npm start with the production variables.
  2. Read the build log on the hostNot just the last line: the first error is the real one.
  3. Check the runtime logsA 500 page hides the error; your host's function or container logs show it.
  4. Compare the variablesList what's set locally and what's set on the host, side by side.

This site runs Next.js on Cloudflare Workers through OpenNext, deployed from GitHub Actions, so I've met most of these first-hand.

If your AI-built Next.js app won't deploy, or deploys and breaks, I fix it and set up a deploy you can repeat. See fixing an AI-built app.

Questions people ask

Why does my Next.js app work in dev but not after build?
The production build type-checks, renders some pages ahead of time and runs without dev's helpful fallbacks. Run npm run build && npm start locally; the first error in the build log is usually the cause.
Why are my environment variables undefined in production?
They're set in .env.local but not on the host, or they have the NEXT_PUBLIC_ prefix and were missing when the app was built. Add them on the host and rebuild.
Why does my Next.js page show old data in production?
It was rendered as a static page at build time. Make it dynamic, or set a revalidate time so it refreshes.
Do I need Docker to deploy Next.js?
No. Vercel, Netlify and Cloudflare deploy it without Docker. Docker helps when you run it on your own servers, AWS ECS or similar, and then output: standalone keeps the image small.

Reply within a day

Got an app, or an idea?

Send me the link, or a few lines about what you want to build. I'll reply within a day with honest next steps, even if I'm not the right fit.

Free 30-minute call · No commitment · Reply within a day

Pick a time on my Cal.com page. Calls are on Google Meet. Or email me.

  1. Step 1

    You send a link or an idea

    A few lines is enough.

  2. Step 2

    I reply within a day

    With questions or a first take.

  3. Step 3

    A free 30-minute call

    Then a written quote.