Skip to main content
Troubleshooting8 min readPublished September 20, 2026Updated September 22, 2026

Why does my app work locally but not after deployment?

Your laptop and your deployment are different environments. The usual culprits are environment variables that exist in one place only, URLs still pointing at localhost, a stricter production build, case-sensitive file systems, and real users hitting access rules you never triggered as the owner.

The problem

The feature works perfectly in development. The same commit, deployed, fails — sometimes at build time, more often at the first real interaction.

What it means

The code is probably fine. Something around the code differs: configuration, the machine it builds on, the data it meets, or the person using it. That is why reading the source repeatedly rarely helps here.

Common causes

CauseTypical symptom
Missing environment variable401, 500, or an empty feature
URL hardcoded to localhostLogin redirects nowhere, callbacks fail
Stricter production buildDeployment fails on type errors
Case-sensitive file systemModule not found for a file that exists
Stale dependency locallyBuild fails only on the clean container
Access rulesEmpty lists for everyone except you
Different databaseMissing tables or missing data

How to diagnose it

  1. 1Did the build succeed? If not, read the build log — the answer is in it verbatim.
  2. 2If the build succeeded, open the live site in a private window and reproduce the failure.
  3. 3Read the failing request's status and body in the Network tab.
  4. 4For a 500, open the function logs for that deployment.
  5. 5Compare the environment variable names in your local file against the hosting configuration, one by one.

How to fix it

  • Add the missing variables to the production environment and redeploy — most changes only take effect on the next deployment.
  • Replace hardcoded URLs with the request's own origin.
  • Fix type errors rather than disabling the check that caught them.
  • Rename files so the import matches exactly, including capitalisation.
  • Run the production build locally once to reproduce the strict environment before deploying again.

What AI may have done

  • Used `http://localhost:8080` for a redirect or callback URL because that is what worked while building.
  • Added a new secret to your local file and mentioned production only in passing.
  • Relied on a package installed for an earlier experiment and since removed from the lockfile.
  • Tested by looking at the preview as the owner, where access rules never say no.

How to verify the fix

  1. 1Redeploy and confirm the new deployment is the one your domain serves.
  2. 2Walk the main flow on the live URL in a private window.
  3. 3Do it again signed in as a second account.
  4. 4Check the function logs for errors during that walkthrough, not just the visible result.

How to prevent it

  • Keep a checked-in list of required variable names, with no values, so nothing is silently missing.
  • Use preview deployments to test changes in a production-like environment before your domain sees them.
  • Test as a second account routinely, not just before launch.
  • Derive URLs from the environment rather than writing them down.

Frequently asked questions

Why does my build pass locally but fail on deploy?
The deployment builds from your repository in a clean container. Anything local — an installed package, an uncommitted file, a looser type check — is not there.
Do I need to redeploy after changing a variable?
Yes. Values are read at start-up, and browser-visible ones are baked in at build time.
Can I copy my local environment file into production?
Copy the names, review the values. Test keys and localhost URLs do not belong in production.

Practice this in MessyDev

Reading it once helps. Doing it once sticks. These are the hands-on parts of MessyDev that cover the same ground.

Keep going