We've been the on-call for enough Node backends to have opinions. This page is the runtime behaviour we design around — the event loop, backpressure, timeouts, and the moments where reaching for a different tool is the professional answer.
Every synchronous CPU-bound function blocks every other user. This is why "Node is slow" reports are almost always "someone put a sync JSON parse in the hot path". Move it to a worker, stream it, or precompute.
Nothing takes longer. If it might, it's a background job.
With one retry, jittered backoff, then circuit-break.
Never unbounded. Postgres has ~100 slots; we plan against it.
Uploads go through pre-signed URLs to object storage, not our RAM.
Per-IP + per-token. Before the app burns CPU parsing junk.
One id through gateway → app → DB → external. Debugging without it is guessing.
Drain the socket, finish inflight, then exit. Kubernetes will thank you.
Health = process alive. Ready = deps reachable. They are not the same.
Errors route somewhere a human sees them. Otherwise they don't exist.
| Platform | Best for | Watch out for |
|---|---|---|
| Vercel / Netlify Functions | Spiky HTTP APIs behind a Next.js site | Cold starts, 10s function limit, no long connections |
| Cloudflare Workers (Node compat) | Global-edge APIs, low-latency reads | Not full Node — check every dep |
| Fly.io / Railway | Long-running processes, WebSockets, cron | You do the ops (which is often the right choice) |
| AWS ECS / Fargate | Enterprise / VPC / SOC2 environments | AWS complexity tax is real |
| Bare EC2 / Hetzner | Predictable heavy load, cost-sensitive | You now run a Linux server. Have a plan. |
The JS execution is single-threaded. The I/O layer (libuv) is a thread pool. Most bottlenecks are in-JS work — parsing giant JSON, sync crypto, unbounded loops — not the network. Move CPU-heavy work to a worker thread or a separate service.
Tell us your goals — we'll recommend the right technology honestly, even if it isn't this one.