Skip to the solution
MediumSystem Design6 min read

When would you choose Node.js over other backend technologies?

1.1k views

The problem

Question presented to candidate: "A team is choosing a backend technology for a new service that will mostly proxy requests to several downstream APIs and aggregate the results. Would you recommend Node.js, and what would make you recommend something else instead?"

What a strong answer should cover:

  • Node fits well specifically for I/O-heavy, high-concurrency workloads β€” API gateways/proxies, real-time services (chat, notifications), and services that spend most of their time waiting on downstream calls rather than computing β€” exactly the scenario in the prompt, and exactly the workload shape verified with real measured concurrency (5 concurrent, genuinely non-blocking requests completing in ~356ms rather than ~1500ms) in the dedicated concurrency question.
  • πŸ“Œ A precise, bounded recommendation, not a blanket one: Node is a weaker fit for CPU-bound-heavy services (video encoding, heavy numerical computation, image processing at scale) β€” the single-thread model does not parallelize that kind of work, verified directly elsewhere in this bank (a large synchronous computation blocks the entire event loop identically to any other blocking call).
  • Team and organizational factors are real, legitimate reasons to choose Node beyond the pure technical fit: a team already fluent in JavaScript/TypeScript, sharing validation logic or types between a JavaScript frontend and backend, and npm's large package ecosystem are genuine, non-technical advantages worth naming explicitly rather than treating the decision as purely an architecture question.
  • A precise answer names Node's genuine competition by workload shape rather than vaguely: Go and other statically-typed, compiled languages are frequently stronger for CPU-heavy or extremely high-throughput services; Python (with an async framework) covers similar I/O-bound ground with a different ecosystem and team-skill trade-off; a JVM-based stack often wins for very large, long-lived enterprise codebases valuing strong typing and mature tooling at scale.
  • Mitigations exist for Node's CPU-bound weakness β€” Worker Threads for in-process CPU-bound work, or delegating genuinely heavy computation to a separate service written in a better-suited language β€” meaning "Node cannot do X" is often more precisely "Node's single thread should not do X directly," a nuance worth stating rather than treating the limitation as absolute.
  • A precise answer resists a one-size-fits-all recommendation and instead names the specific, checkable properties of the actual workload (I/O-bound vs. CPU-bound, team's existing skills, ecosystem needs) that should drive the decision β€” exactly the structure demonstrated in this answer, rather than declaring Node "good" or "bad" in the abstract.

Clarifying questions expected:

  • "Is the workload genuinely I/O-bound, or does it also include significant CPU-bound processing?" β€” the single most decisive technical factor.
  • "Does the team already have deep expertise in a different ecosystem, or would adopting Node itself be a significant new cost?" β€” a real, legitimate factor beyond pure technical fit.

Code / implementation expected: No β€” this is a judgment/trade-off question; grounding the recommendation in the real, measured concurrency evidence from the dedicated concurrency question is the appropriate level of rigor here, not new code.

  • use cases
  • scalability
  • real-time
  • architecture

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

6 min read Β· 10 sections

Read the code

JavaScriptA quick, checkable litmus test for whether a workload actually fits Node's concurrency model
// The same heartbeat technique used throughout this bank to distinguish a
// genuinely I/O-bound workload (good Node fit) from one that is secretly
// CPU-bound (poor Node fit, at least for that specific hot path):
let ticks = 0;
const hb = setInterval(() => ticks++, 10);

const t0 = Date.now();
await theCandidateOperation(); // the real operation being evaluated
console.log("took", Date.now() - t0, "ms; heartbeat ticks during it:", ticks);
clearInterval(hb);

// ticks stayed near the expected count for the duration -> genuinely I/O-bound,
//   a good fit for Node's single-thread concurrency model (verified: 5
//   concurrent 300ms waits completed in ~356ms, not ~1500ms, elsewhere in
//   this bank).
// ticks dropped to near 0 -> the operation is secretly CPU-bound and will
//   block every OTHER concurrent request on the same thread β€” a real signal
//   to move it to a Worker Thread, a separate service, or reconsider Node
//   for that specific hot path.

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 43 of 152 in Node.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Node.js questions
Up nextMedium

How do you manage configuration in a Node.js application for different environments?

Continue