Spots

Your Backend Works Locally. That Doesn’t Mean It’s Production-Ready

The API responds correctly. The database connection works. You run the app locally for the tenth time and everything looks fine. And suddenly the problem changes completely. A backend that works on your laptop is not necessarily a backend that is ready for production. Local development proves that your application can run in your environment. Production asks a much harder question: Can this thing keep working when the environment is no longer under your control? That difference is where a lot of small teams get caught. Local development hides a lot Your development machine is unusually forgiving.

the correct environment variables direct access to the

the correct environment variables direct access to the database the right runtime installed every dependency available full filesystem permissions a predictable network logs directly in your terminal one developer making requests a database you can reset without consequences Production gives you none of those guarantees.

The application now needs to survive restarts, failed

The application now needs to survive restarts, failed migrations, missing secrets, expired credentials, network interruptions, disk limits, bad deployments and actual users. That means “it runs locally” is only the beginning. Configuration becomes infrastructure Locally, this might be enough: DATABASE_URL=postgresql://localhost:5432/app JWT_SECRET=dev-secret PORT=3000 In production, configuration has consequences. What happens if JWT_SECRET is missing? Does the application refuse to start? Or does it silently fall back to something unsafe? A production backend should fail predictably. const required = [ "DATABASE_URL", "JWT_SECRET" ];

for (const variable of required) { if (!process.env[variable])

for (const variable of required) { if (!process.env[variable]) { throw new Error( Missing required environment variable: ${variable} ); } } It is simple, but it is much better than discovering the problem after deployment. Configuration should be validated before the application begins accepting traffic. Database migrations stop being harmless During development, database changes are easy. Production is different because the database contains data you cannot casually destroy. ALTER TABLE users DROP COLUMN username;

Now imagine doing that with 50,000 production users

Now imagine doing that with 50,000 production users and discovering another part of the application still depends on username. The migration technically succeeded. The deployment still failed. Production migrations need to consider:

backwards compatibility existing data rollback strategy application version

backwards compatibility existing data rollback strategy application version compatibility long-running operations database locks For risky changes, the safer pattern is often incremental. remove old field deploy new code hope add new field deploy compatible code migrate data verify remove old field later The boring version is usually the safer version. “The server is running” is not a health check Your process can be alive while your application is effectively dead.

PostgreSQL is unreachable Redis is unavailable migrations failed

PostgreSQL is unreachable Redis is unavailable migrations failed storage credentials are invalid an external dependency is timing out Your process manager may still happily report: That is why production systems usually need an actual health endpoint. app.get("/health", async (req, res) => { try { await db.query("SELECT 1"); } catch { res.status(503).json({ status: "unhealthy" }); } }); Now your infrastructure has something meaningful to test. Is Node.js still running? Can this application actually serve requests? That distinction matters. Logging changes when nobody is watching the terminal often feels perfectly adequate. You are already looking at the terminal. Production errors usually happen while nobody is looking. is almost useless three hours later.

Useful production logs should tell you things like

Useful production logs should tell you things like: what happened when it happened which request triggered it which service failed how severe the failure was Structured logs are much easier to search and process. console.log("Database error"); logger.error({ event: "database_connection_failed", requestId, error: error.message }); gives you something you can actually investigate. Production observability is not about printing more text. It is about leaving enough evidence to understand failures after they happen. Backups do not matter until restoration works A lot of systems technically have backups. Far fewer know whether those backups can actually be restored. There is an uncomfortable difference between: “We create a backup every night.” “We successfully restored yesterday’s backup into a clean database.” The second statement proves something.

The first only proves that a file exists

The first only proves that a file exists somewhere. A production backup strategy should answer:

How often do backups run? Where are they

How often do backups run? Where are they stored? How long are they retained? Are they encrypted? How quickly can they be restored? When was restoration last tested? A backup you have never restored is still partly a hypothesis. Deployment without rollback is a one-way door Imagine deploying version 1.8. error rates spike users cannot authenticate database queries slow down one endpoint starts returning 500 “Give me twenty minutes while I fix it.” you do not really have a recovery strategy. Sometimes the fastest fix is simply returning to the last known-good version. That requires your deployment system to know: and to make returning to: Production reliability is not about never breaking anything. Eventually something will break. Reliability is largely about reducing how expensive failure becomes. Production traffic exposes assumptions During local development you might be the only user.

News

Your Backend Works Locally. That Doesn’t Mean It’s Production-Ready

The API responds correctly.

@spots #dev
Source: Dev.to
See more like this