Why your deploy fails when it works locally — 3 causes to check first

A familiar pain: the app runs locally first try, you proudly hit "deploy" — and get a cold Build failed. First thought: "but it works for me!" Here's the calming part: the server isn't being fussy, it almost always trips over one of three things. And each one shows up in the build logs. Open them first (in Vercel, Netlify, Render it's the deploy-logs tab) — the cause is usually spelled out in the red line. Let's go through the top three, starting with the most common.
If deploying is new to you, start with what "deploy" means.
The symptom
Locally all fine, but on the host the build fails with an error — or it builds, yet the site loads blank or with a 500. Here's why.
Cause 1. Environment variables didn't make it (the most common)
Locally, your keys and addresses sit in a .env file. And that file is deliberately kept out of git — otherwise you'd leak secrets. So it isn't on the server, and the code crashes: "API key not found," "undefined."
How to check: in the logs, look for undefined, missing, a variable name, or API key not found. Make a list of everything you read from the environment.
How to fix: the host's dashboard has an Environment Variables section. Enter every variable from your .env there by hand, with the same names. Rebuild. On the mechanism itself — environment variables.
Cause 2. Versions and dependencies don't match
"Works on my computer" often means "works on my Node version and my packages." The server's version is different, or you installed a package locally but never recorded it in the project.
How to check: in the logs — module not found, cannot find package, or a Node-version error. Confirm your lock file (package-lock.json, pnpm-lock.yaml) is committed, and that the needed package is in package.json, not just in your folder.
How to fix: add the missing package to dependencies (npm install name, then commit the package.json + lock-file changes). If it complains about Node, set the version explicitly in the host's project settings — the same one you run locally.
Cause 3. Letter case in paths (the Mac/Windows → Linux trap)
The invisible killer. On Mac and Windows the file system doesn't tell Header.js and header.js apart — to them it's one file. Servers run on Linux, and it distinguishes case strictly. Importing ./components/header when the file is Header.js works locally but throws module not found on the server.
How to check: the log says module not found, yet the file clearly exists. Compare the case in the import and the filename letter for letter.
How to fix: make them match — rename the file or fix the import. For the future: keep one naming style and these surprises stop.
What to do when the log is cryptic
Copy the whole red line from the log and hand it to your AI helper: "here's the deploy error, here's my stack — what's the cause and how do I fix it?" The full error text solves half the problem. More in how to debug with AI.
Why does it work locally but not on the server?
Because they're two different environments: a different OS, different versions, and no .env of yours. "Works for me" only tests your computer. The deploy tests everything else — which is why it catches what you didn't see at home.
Where do I even look for the cause?
In the build logs on the host, not in the browser. With Vercel, Netlify, Render it's a dedicated tab with step-by-step deploy output. The red line there is your main clue — always start with it.
Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.





