Most Node.js Crashes Are Avoidable
The majority of production Node.js incidents are not exotic. They are an unhandled promise rejection, an error swallowed silently, or a process that crashed because nobody caught a thrown exception. Good error handling is not glamorous, but it is the difference between an app that degrades gracefully and one that falls over at 2am. Here is how to get it right.
Know Your Two Kinds of Errors
Every error falls into one of two buckets, and treating them differently is the foundation of good handling:
- Operational errors — expected problems in a correctly written program: a failed database query, an invalid user input, a third-party API timing out. These you handle and recover from.
- Programmer errors — bugs: calling a function that does not exist, reading a property of undefined. You do not "handle" these; you fix them. In production, the safest response is often to log and let the process restart cleanly.
Confusing the two — trying to recover from a bug, or crashing on an expected failure — is the root of most bad error handling.
Async Errors Are Where People Get Burned
A try/catch around synchronous code is straightforward. The trouble is async. An unhandled rejection in a promise, or a thrown error inside an async route handler that nobody awaits, can silently take down a request or the whole process. The rules:
- Always await inside try/catch for async operations, or attach a
.catch(). - Wrap async route handlers so thrown errors reach your error middleware instead of vanishing.
- Listen for
unhandledRejectionanduncaughtException— log them, then let the process restart. Do not try to keep running after an uncaught exception; the process state is no longer trustworthy.
Centralize Error Handling
Do not sprinkle ad-hoc error responses across every route. In Express, use a single error-handling middleware at the end of the chain that receives all errors, decides the right status code, logs appropriately, and returns a consistent response shape. One place to reason about, one format for clients to expect.
What to Send vs What to Log
Two audiences, two messages. The client gets a clean, generic message and a correct status code — never a stack trace or internal detail, which is both confusing and a security risk. Your logs get the full picture: stack trace, request context, and enough detail to reproduce the problem. Tie them together with a request ID so a user's report maps to a specific log entry.
Production Logging
- Use structured logging — JSON logs are searchable;
console.logstrings are not. - Include context — request ID, user ID (not sensitive data), route, and timing.
- Pipe to a real tool — ship logs somewhere you can search and alert on, not just the server's disk.
How Dharmsy Builds Resilient Backends
We build Node.js services with a clear operational-versus-programmer error split, centralized error middleware, structured logging, and process supervision that restarts cleanly on fatal errors. If your Node app crashes in ways you cannot explain, an error-handling and logging review usually surfaces the cause fast.

