[ For the work that waits on other systems ]
Node is at its best when a request spends its life waiting — on a database, an API, a queue, another service. It is the wrong tool for heavy computation, and we will say so rather than sell you the stack we happen to like.
Node is at its best when a request spends its life waiting — on a database, an API, a queue, another service. It is the wrong tool for heavy computation, and we will say so rather than sell you the stack we happen to like.
Tell us what the service has to wait onAdding types to a grown JavaScript service is a project of its own. Starting typed costs nothing and pays every time someone new opens the code.
Reports, imports and third-party calls run on BullMQ workers. A slow job on the request thread blocks every other user of a Node process.
The same TypeScript across API and front end is a real saving on a small team. It is not a reason to use Node for a job it suits badly.
Structured logs, health checks, graceful shutdown and a process manager. A Node service that cannot be restarted cleanly is a Node service that loses requests.
REST and GraphQL services that sit between your apps and your data, with a written contract, validated input and errors a client can act on.
The middle layer between systems that were never designed to talk: payment, courier, ERP and marketplace, on queues so a slow partner cannot take your API down with it.
Chat, live tracking, notifications and dashboards over WebSockets, with a Redis adapter so it still works when there is more than one instance.
Is this I/O-bound or CPU-bound? Node is excellent at the first and poor at the second, and that answer decides the stack before anything else.
Routes, payloads and errors agreed as a contract before code. Front-end and back-end then build against the same document instead of against each other.
PostgreSQL unless the shape genuinely wants a document store. Mongo chosen by habit rather than by shape is the commonest regret on these projects.
Typed handlers, validated input, a service layer that is testable without HTTP, and integration tests against a real database rather than a mock.
Queues and workers for anything that waits on a third party or takes seconds, with retries, dead letters and somewhere for failures to be seen.
Docker, health checks, structured logging, metrics and a graceful shutdown that drains in-flight requests before the process exits.
Node earns its reputation on one specific shape of work: many concurrent requests that spend nearly all their time waiting on something else. An API gathering data from three services, a webhook receiver, a realtime feed — Node handles those on one thread with very little memory, and does it well.
It is a poor choice for heavy computation, because that work blocks the single event loop and every other request behind it. When we see image processing, large report generation or anything CPU-bound in the requirements, that part goes to a queue or to a different runtime — and we say so at the estimate rather than after launch.
TypeScript on day one costs almost nothing. Retrofitting it on to a grown service is a project nobody budgets for and everyone eventually needs.
One blocking operation stalls every concurrent request. Anything that takes seconds goes to a worker, and that rule is set before the first route is written.
Relational data in a document store is a decision that gets expensive at exactly the point it is hardest to reverse.
Native test runner, native watch mode and stable ESM mean far less of a Node project is now configuration. New services start smaller than they did two years ago.
Express still runs everywhere, but new work tends to start on something with validation, typing and structure built in rather than assembled from ten packages.
A dependency tree of hundreds of packages is an attack surface. Lockfiles, audit gates in CI and a deliberately short dependency list are now part of the build.
Teams have gone back to picking per workload — Node for I/O, Python for data and models, Go where throughput matters. That is a healthier default than one runtime for all of it.
Yes, when the work is I/O-bound and the codebase is typed and structured. Large Node systems fail for the same reasons large systems in any language fail — no types, no service boundaries, no tests. They fail specifically in Node when CPU-heavy work is left on the event loop, which is avoidable by design.
Let’s talk about your node.js project. No obligation, just a conversation.
Next service
PHP Development