Because the server isn't your computer. Your app is quietly relying on something that exists on your machine and not on the server: a setting, an address that points back at your computer, the database, the port it listens on, or the capital letters in a file name. The server's logs usually name which one.
What's the problem
The app runs fine when you or your developer start it. Put it online and you get an error page, a blank screen, a login that fails, or a deploy that never finishes. Nothing in the code changed between the two, which is what makes it feel impossible.
Why it happens
Almost every case comes down to one of five differences.
- Settings that only exist on your computer. Apps keep passwords, API keys and addresses in environment variables, often in a
.envfile that is deliberately left out of the code. The server never got a copy, so it starts with blanks. - Addresses that point at your computer.
localhostmeans "this machine". On your laptop, that's where the backend runs. On the server, or in a visitor's browser, it isn't. Frontend tools such as Vite bake these values into the app when it's built, so a build made with your local settings keeps calling your laptop. - A different database. A small file database on the laptop and PostgreSQL in production, or a production database that's empty, missing tables, or unreachable. Small differences between the two are enough to break code that worked locally.
- The wrong port. Hosting platforms tell your app which port to listen on, usually through a
PORTsetting, and expect it to listen on0.0.0.0(every network connection) rather thanlocalhost. An app hard-wired tolocalhost:3000is running but unreachable. - Capital letters in file names. Windows and macOS usually treat
Logo.pngandlogo.pngas the same file. Linux servers, which is what most hosting runs on, don't. An import that works on your laptop can't find the file online.
How to fix it
- Read the server's logs first. Your host shows them in its dashboard for each deploy. The first error there names the cause more often than not.
- List every setting the app reads. Search the code for
process.env,import.meta.envoros.environ. Set each one in the hosting dashboard, with production values. - Search the code for
localhostand127.0.0.1. Replace hard-coded addresses with a setting, then rebuild the frontend with the production address. - Check the database. The server can reach it, the tables exist (run the migrations), and it's the same kind of database you use locally.
- Listen where the host tells you. Use the
PORTsetting the host provides, on0.0.0.0. - Match file names exactly. Every import should use the same capital letters as the file on disk.
- Run the production build on your own machine. Build and start it the way the server does. Many of these problems show up before you deploy.
When to call Preventionlabs
If one of these steps gets it running, you're done, and you didn't need us. Call us when you've worked through them and it still won't stay up, or when nobody is left who knows how the app was meant to run. Getting an app from "works on my machine" to live is the job: it builds, it starts, it's deployed in your own hosting account, and the user flows you list work end to end. The free assessment tells you in writing what's stopping it.
Submit your project for a free assessmentFree assessment. $10,000 AUD flat to get it live, only if we take it on and you go ahead.
Sources
- The Twelve-Factor App: III. Configengineering methodology
An app’s config is everything that is likely to vary between deploys (staging, production, developer environments, etc).
- The Twelve-Factor App: X. Dev/prod parityengineering methodology
Differences between backing services mean that tiny incompatibilities crop up, causing code that worked and passed tests in development or staging to fail in production.
- Render: Web Services: Port bindinghosting platform docs
Every Render web service must bind to a port on host 0.0.0.0 to serve HTTP requests.
- Vite: Env Variables and Modesbuild tool docs
The values of these variables are bundled into your source code at build time.
- Git: git-config: core.ignoreCaseofficial docs
Internal variable which enables various workarounds to enable Git to work better on filesystems that are not case sensitive, like APFS, HFS+, FAT, NTFS, etc.