Skip to content
Gun.io
October 8, 2026 ยท 19 min read

Node.js Developer Interview Questions for Hiring Managers

A Node.js developer can build a convincing demo without ever having run a service under real traffic. The difference tends to appear later, in ways a demo rarely exercises: a synchronous parse that stalls every request, a rejected promise nobody handled, or a dependency added without much thought. A useful Node.js interview finds out which of those situations the candidate has already worked through.

Most things that go wrong in a Node.js service come from a small number of places: the event loop, asynchronous error handling, API behavior under retries, diagnosis under load, and security defaults. A candidate who explains those areas clearly, and can describe what happened when they got one wrong, gives you more useful evidence than one who recites framework APIs.

The 20 Node.js developer interview questions below are grouped around those areas. Each one includes notes on what a good answer covers and a follow-up to ask. The notes give a hiring manager a basis for the conversation, not a single approved answer. For a substantive technical decision, involve an engineer who can judge the code and the alternatives; a candidate who reaches a different, well-reasoned answer may be giving you the better one.

How Should You Structure a Node.js Interview?

Start with the service the engineer will own. An internal API with modest traffic, a payment integration, and a streaming data pipeline put different pressure on the same runtime. Choose the Node.js interview questions that reflect that work, and leave time for follow-ups rather than trying to cover all 20 in one sitting.

For senior roles, follow a correct answer with a change in conditions: a dependency that starts timing out, traffic that doubles, a payload that grows a hundredfold. How someone revises a solution usually tells you more than the first answer. Keep in mind what the session can and cannot show. An interview gives you evidence about how a person reasons; how they perform on the actual work is the real evidence.

Event Loop and Asynchronous Execution Questions

1. How Does the Node.js Event Loop Handle Concurrent Requests?

JavaScript in a Node.js process runs on a single main thread. Network I/O is handed to the operating system, while some operations, such as file system calls and dns.lookup, run on the libuv thread pool. When that work completes, it queues its callback, and the event loop runs it. The loop moves through phases in a fixed order: timers, pending callbacks, an internal idle and prepare stage, poll, check (where setImmediate callbacks run), and close callbacks. Source: Node.js event loop guide

Then ask where process.nextTick and promise callbacks fit. A precise answer says they run after the current operation completes, before the loop continues, rather than in their own phase.

The useful signal is whether the candidate connects the model to its limit. One process can hold thousands of open connections because each request spends most of its time waiting on I/O, and that stops being true the moment a request does heavy computation on the main thread.

2. What Happens When CPU-Heavy Work Blocks the Event Loop?

Give a concrete case: a route parses a 50 MB JSON file synchronously. Every other request waits until the parse finishes, health checks can time out, and latency rises for users whose requests have nothing to do with the file.

Ask what they would change, and why. Moving the work to a worker thread or a separate service, partitioning it into chunks that yield back to the loop, and streaming the input are all reasonable, depending on the size and frequency of the work. The Node.js documentation recommends partitioning for simple tasks and offloading for complex ones, and it notes that a service that relies heavily on complex calculations may not be a good fit for Node.js at all. Source: Node.js guide to not blocking the event loop

Adding servers spreads the load but does not remove the block; each instance still stalls on the same input.

3. How Do You Handle Errors With Promises and async/await?

A good answer handles errors where the code can do something useful with them and sends everything else to a central handler. Wrapping every line in try/catch and logging the error without returning a response or rethrowing leaves the request hanging and hides the failure.

Follow up on unhandled rejections. In current Node.js releases, an unhandled rejection is raised as an uncaught exception by default, so the process can exit unless the application handles it. Source: Node.js process documentation

Then ask about Promise.all. It rejects as soon as one promise fails, but the other operations keep running unless the code cancels them, for example with an AbortController. Promise.allSettled fits cases where partial success is acceptable. A candidate who can explain that difference understands what the API does and does not promise.

4. When Would You Use Worker Threads Instead of the libuv Thread Pool?

The thread pool runs specific built-in operations that Node.js offloads internally. Worker threads run your own CPU-bound JavaScript in parallel. Ask the candidate to explain the difference and when each matters.

Factor libuv thread pool worker_threads
Who uses it Node.js internals Your application code
Typical work File system calls, dns.lookup, crypto.pbkdf2, asynchronous zlib Image processing, large parsing jobs, hashing loops
Default size 4 threads, adjustable with UV_THREADPOOL_SIZE You create and pool them
Memory model Managed by the runtime Separate JavaScript environment; communicates by messages or SharedArrayBuffer

A senior candidate may point out that the pool is shared, so heavy crypto or compression work can occupy the default four threads and leave unrelated file system calls queued behind it while event loop metrics look healthy. Source: libuv thread pool documentation

Ask when worker threads would not help. They add startup cost and memory, and they do little for work that spends its time waiting on I/O.

5. How Do You Limit Concurrent Calls to an External Service?

Use a realistic prompt: “You need to call a payment provider for 10,000 records, and the provider allows 20 concurrent requests.” Promise.all(records.map(callApi)) sends all 10,000 at once, which triggers rate limiting and failed calls. A good answer describes a pool or queue that processes a fixed number of requests at a time.

Then ask what happens when the provider slows down or starts returning errors. Relevant answers include timeouts on every outbound call, retries with exponential backoff and jitter that respect a Retry-After header, and a circuit breaker that pauses calls during sustained failure.

Ask one more question: is it safe to retry this particular call? For a payment, the answer depends on idempotency, which leads to the next group of questions.

API Design and Reliability Questions

6. How Would You Design an API Endpoint for Safe Retries?

Networks can drop a response after the server has already done the work, so clients will retry. The usual answer is an idempotency key: the client sends a unique key with the request, and the server records the first request’s outcome so it can return the same result on retry. GET, PUT, and DELETE are idempotent by HTTP definition; POST is not.

Ask how the server handles two identical requests that arrive at the same moment. A unique constraint or a lock on the key is a reasonable answer. Then ask about the boundary. If the side effect lives in your own database, the key and the change can be stored in one transaction.

If the side effect is a charge at an external provider, your transaction cannot include it. The candidate should use the provider’s own idempotency support and reconcile unknown outcomes, because a timeout does not tell you whether money moved.

7. How Does Express Middleware Order Affect Request Handling?

Express runs middleware in the order it is registered, so order affects security, parsing, and error behavior. Ask the candidate to lay out a typical stack and explain the reasoning. One defensible order is:

  1. Security headers and CORS.
  2. Request ID and logging.
  3. Rate limiting.
  4. Body parsing, with size limits.
  5. Authentication, then authorization.
  6. Route handlers.
  7. A 404 handler.
  8. The error handler.

Variations can be fine if the candidate can justify them. The details that matter are that protected routes sit behind authentication, and that error-handling middleware takes four arguments (err, req, res, next) and is registered after the other middleware and routes. Source: Express error handling guide

8. How Would You Handle Errors Across an API?

Look for one central error handler and a consistent error format: a code, a message the client can act on, and a request ID for tracing. Keep internal details, such as stack traces, in the logs. Ask the candidate to separate operational errors, such as invalid input or a dependency timeout, from programmer errors, such as reading a property of undefined. The first deserves a clean response. The second may leave the process in an unknown state, which is why some teams log it and restart.

Version context matters here. In Express 5, a route handler that returns a rejected promise passes the error to the error handler automatically. Express 4 required the developer to catch the error and call next(err) or use a wrapper. Ask which version the candidate has worked with and what changed when they upgraded, if they did.

9. How Do You Validate Requests and Choose Response Codes?

Validate every request at the boundary against a schema, and reject what doesn’t match. Zod, Joi, and JSON Schema with Ajv are common tools; the choice matters less than applying it consistently.

Client-side checks help the user, but the server has to be the authority. We worked with a clinical research platform whose validation logic lived only in the mobile app, so an assessment that crashed or lost its connection before a full sync lost its data; moving validation to the backend made the server the source of truth. Then ask which status code the client should receive in each situation.

Situation Code to discuss
Malformed body or failed validation 400, or 422 for semantic validation errors
Missing or invalid credentials 401
Authenticated but not permitted 403
Resource not found 404
Duplicate or state conflict 409
Rate limit exceeded 429
Upstream dependency failed or timed out 502, 503, or 504

Ask why returning 200 with { success: false } causes problems. Client retry logic and monitoring both read status codes, so a failure reported as success can make an outage look like healthy traffic.

10. How Would You Test an Endpoint That Depends on an External API?

A useful answer tests at more than one layer. Unit tests replace the external client with a stub. Integration tests intercept HTTP calls with a tool such as nock or MSW. A small number of contract tests may run against the provider’s sandbox, outside the main CI pipeline so builds stay deterministic.

Ask which failure paths they would cover. Timeouts, 429 responses, server errors, and malformed payloads are the cases most likely to fail in production, and they are also the cases a manual check in an API client tends to skip. The test runner, whether the built-in node:test, Jest, or Vitest, matters less than whether the candidate can explain what each test proves.

Performance and Production Operations Questions

11. How Would You Diagnose Rising Latency Under Load?

The stronger signal is a candidate who measures before changing anything. A reasonable sequence starts with p95 and p99 latency per route, since an average hides the slow tail, then checks event loop delay and CPU, distributed traces for slow queries or upstream calls, and connection pool saturation.

A pool of 10 database connections serving 200 concurrent requests builds a queue that looks like slow code. The cause isn’t always in the application: in one enterprise security platform, heavy reporting queries ran against the same databases as live operations, and the fix was to separate the two workloads.

Ask what they would do if those checks pointed to the application itself. Capturing a CPU profile with –cpu-prof or the inspector and reading the flame graph is a good answer. Proposing a cache before any diagnosis is a guess: it may help, or it may hide the real bottleneck until the cache misses.

12. When Should You Use Streams and Backpressure?

Streams fit data that is large, unbounded, or arrives over time: uploads, exports, log processing, and proxying. Backpressure keeps a fast producer from filling memory faster than a slow consumer can drain it. When a writable stream’s buffer passes its highWaterMark, write() returns false, and the producer should wait for the drain event before writing more. Source: Node.js backpressure guide

Ask for a real example, such as streaming a CSV export row by row instead of building it in memory. Then ask about errors. stream.pipeline forwards errors and cleans up every stage when one fails, while a chain of .pipe() calls without error handling can leave streams and file handles open.

13. How Would You Detect and Investigate a Memory Leak?

A good answer starts with evidence: heap usage that climbs across garbage collection cycles and never returns to its baseline. From there, the candidate takes heap snapshots at intervals, using –heapsnapshot-signal or the inspector, compares them in Chrome DevTools, and follows the objects with the largest retained size back to whatever holds them.

Ask which causes they have found in practice. Common examples include unbounded in-memory caches, event listeners that are added and never removed, closures that keep request objects alive, and timers that are never cleared. Scheduled restarts can limit the damage while someone investigates, but they do not fix the leak, and the interval tends to shrink as traffic grows.

14. How Would You Scale a Node.js Service Across CPU Cores?

There are two common approaches: several processes on one machine, using the cluster module or a process manager, or one process per container scaled horizontally by an orchestrator. In Kubernetes, one process per container with horizontal autoscaling is the usual pattern, and running cluster inside the container often adds complexity without much benefit.

Either approach requires a stateless service. Ask where sessions, caches, and WebSocket state live. If they stay in local memory, users can lose sessions when the load balancer sends them to a different process. A candidate should also separate this question from worker threads, which parallelize CPU work inside a single process.

15. Which Metrics Show That the Event Loop Is Falling Behind?

Event loop delay is the primary signal. perf_hooks.monitorEventLoopDelay() samples the delay over time and reports a histogram with percentiles, and event loop utilization shows how much of the time the loop has no idle capacity. Garbage collection pauses, and a growing count of active handles or pending requests add context. Source: Node.js performance measurement APIs

Ask what level of delay would concern them. The answer should depend on the service’s latency budget, not a universal number. Then ask why CPU usage alone can mislead: a single-threaded process on a multi-core host can show modest total CPU while its one event loop is fully occupied.

Security Questions

16. How Would You Prevent Injection Through User Input?

Treat all input as untrusted. For SQL, that means parameterized queries or a query builder, never string concatenation. For MongoDB, a login body such as { “$gt”: “” } can bypass a naive check, so schema validation and stripping operator keys matter. For shell commands, execFile or spawn with an argument array avoids the interpolation risks of exec.

Ask about less obvious paths, such as prototype pollution from merging untrusted objects into application state. Manual escaping is a weak answer, because it depends on anticipating every edge case that parameterization already handles.

17. How Do Authentication and Authorization Differ in an API?

Authentication establishes who the caller is. Authorization decides what that caller may do with a specific resource. The common failure is checking the first and skipping the second, so any logged-in user can read another customer’s order by changing an ID in the URL. A good answer checks ownership on every request, for example, that order.userId matches the caller.

Follow up on tokens and credentials. Verifying JWT signatures against a fixed list of algorithms, checking expiry and audience, keeping access tokens short-lived, storing browser session tokens in HttpOnly, Secure, SameSite cookies, and hashing passwords with bcrypt, scrypt, or Argon2 are all reasonable points. Ask which of those the candidate has implemented and which they have only read about.

18. How Would You Protect Secrets in a Node.js Service?

Secrets belong in a managed secrets store and are injected at runtime, with access scoped per service. They stay out of source code, container images, and logs. Ask how the candidate keeps .env files out of version control, whether secret scanning runs in CI, and how logging middleware redacts tokens.

Then ask what they would do if a key were committed to a private repository. A private repository still gets cloned and shared, and the key remains in the git history. The practical answer is to rotate the credential first, then clean up the history.

19. How Do You Manage Risks in npm Dependencies?

Every dependency runs with the service’s privileges, and some packages run install scripts on developer machines and CI runners. Look for a committed lockfile installed with npm ci, npm audit or a software composition analysis tool on every build, version updates through reviewed pull requests, and a habit of checking a new package’s maintenance history and install scripts before adding it.

For regulated environments, ask whether they have produced a software bill of materials. The broader signal is whether the candidate treats dependency choices as engineering decisions with consequences, rather than as a quick way to close a ticket.

20. How Would You Limit Abuse of a Public API?

A good answer layers several controls: rate limiting per client, request size limits, server timeouts that blunt slow-request attacks, and authentication for expensive operations. Ask how the limits hold across instances. A limiter that keeps counters in memory on a service running six instances allows roughly six times the intended rate and resets on every deploy, which is why a shared store such as Redis is common.

Then ask about details that are easy to miss: returning 429 with a Retry-After header, applying tighter limits to login, password reset, and search, and setting Express’s trust proxy correctly so the limiter sees real client addresses rather than the load balancer’s.

Practical Assessment Options

A conversation shows how a candidate reasons. A practical exercise shows how they work on a small, bounded problem. Choose the format that matches what the role requires.

Format Time Best at revealing Trade-off
Paired live coding 45 to 60 minutes Reasoning, debugging, collaboration Can disadvantage candidates who work best with quiet focus
Scoped take-home 2 to 4 hours, capped Code structure, tests, judgment Needs a follow-up discussion to establish understanding
Code review exercise 30 to 45 minutes Production instincts, security awareness Weaker signal on writing new code

When Should You Use Paired Live Coding?

Live coding fits roles with close collaboration or on-call debugging. Start from a working repository with a failing test and a problem drawn from your own domain, such as adding a concurrency limit to a batch job. Let the candidate use their own editor and the Node.js documentation, answer clarifying questions, and avoid steering. Note the questions they ask, how they test, and how they recover from a mistake.

What Makes a Scoped Take-Home Fair?

State a time cap, clear acceptance criteria, and the rubric you will use. A small API with two or three endpoints and one external dependency is enough, with explicit expectations for validation, error handling, tests, and a short README on trade-offs. Follow it with a discussion of the candidate’s choices. That conversation helps establish understanding, although no format conclusively proves authorship. Open-ended take-homes tend to reward free time more than judgment.

What Can a Code Review Exercise Reveal?

Give the candidate a 100- to 150-line Express route with deliberate problems: a synchronous file read in the handler, SQL built by concatenation, a missing await, no ownership check on a resource ID, and an error response that returns err.stack. Ask them to rank what they find by severity. A candidate who finds the security and reliability issues first and explains why they matter is showing the judgment a senior role needs; one who comments mainly on formatting is showing something else.

How Should Mid-Level and Senior Answers Differ?

Use the same questions for both levels with different expectations. Mid-level candidates should answer correctly within an existing design. Senior candidates should also explain trade-offs and failure modes, and how they would prevent the problem across a team.

Area Mid-level evidence Senior evidence
Event loop Explains phases and microtasks Diagnoses blocking from metrics and profiles
Async errors Handles errors at the right boundary Designs process-wide error and shutdown behavior
API design Correct status codes and validation Idempotency, versioning, backward compatibility
Performance Uses streams, avoids synchronous I/O Leads leak and latency investigations
Security Parameterizes queries, hashes passwords Designs the authorization model and dependency policy
Code review Finds the obvious defects Ranks by severity and proposes guardrails

A four-point scale can help each interviewer organize specific evidence before the group discusses a candidate. It is an interview aid, not a validated predictor of performance, and an average should not hide a weakness in something the person will have to own alone.

Red Flags That Signal Production Risk

Probe further when a candidate describes Node.js as handling each request on its own thread, runs Promise.all over unbounded input, logs errors without responding, builds SQL or shell commands from user input, or cannot explain code they submitted. A proposal to restart processes or add servers to fix a leak or a blocked loop also deserves a follow-up.

A single weak answer should lead to another question, not an automatic verdict. A pattern of them in responsibilities the role requires is more consequential.

How Gun.io Vets Node.js Developers

At Gun.io, a Node.js profile is useful when it describes what the engineer has actually run: the traffic, the dependencies, the incidents, and the decisions that were theirs. Framework fluency is part of that picture. The more important question is whether the engineer can carry the backend responsibility the engagement requires, with the amount of direction the client can provide.

We evaluate technical capability and professional fit through human interviews, and because on-the-job performance is the real evidence, selection continues after an engineer joins the network.

Much of the work we see involves backend systems, integrations with external platforms and APIs, and performance problems such as validation logic that made an admin dashboard take more than two minutes to load. Those are the conditions where the questions above matter most, and we use them as context when discussing a Node.js engineer’s fit with a client.

Frequently Asked Questions

What Node.js Developer Interview Questions Should I Ask?

Ask questions on the event loop, asynchronous error handling, API reliability, performance diagnosis, and security, weighted toward the service the engineer will own. Follow each answer with a change in conditions, and pair the conversation with one practical exercise.

What Should I Ask a Junior Node.js Developer?

Ask a junior candidate to explain callbacks, promises, and async/await, and to build a simple Express route with validation and error handling. Look for sound fundamentals and honesty about gaps. Profiling and architecture questions fit mid-level and senior roles better.

How Can a Nontechnical Hiring Manager Evaluate Node.js Answers?

Compare answers against written notes like the ones above, and listen for specific tools, failure cases, and trade-offs. Vague claims deserve a follow-up question. For the final decision, combine your notes with an assessment from an engineer who can review the candidate’s code.

Should I Include Express.js Questions in a Node.js Interview?

Yes, if your codebase uses Express, particularly on middleware order and error handling. Keep most of the weight on runtime behavior, which carries across frameworks, and ask which Express version the candidate has used, since error handling changed in Express 5.

How Long Should a Node.js Technical Interview Take?

Sixty to ninety minutes for the conversation, plus one practical format, is a reasonable starting point. Live coding usually takes 45 to 60 minutes; a take-home should have a stated cap and a follow-up discussion. Adjust the time to the responsibility you need to assess.

What Distinguishes a Senior Node.js Developer From a Mid-Level Developer?

A senior developer diagnoses production problems and designs the systems that prevent them; a mid-level developer implements features correctly within an existing design. Open-ended scenarios such as rising latency or a memory leak show the difference more clearly than definitions.

Choose Node.js Engineers Who Can Run What They Build

Use the Node.js developer interview questions to understand how a candidate reasons about the event loop, failures, and security, and the practical exercise to see how they apply it. If you are planning a Node.js hire, talk to us about what you’re building: the service, its traffic and dependencies, and who will own it in production.

Gun.io

Sign up for our newsletter to keep in touch!

This field is for validation purposes and should be left unchanged.

+1 (615) 541-8095

team@gun.io

© 2026 Gun.io