Node.js Interview Questions for AI Training Work
AI training platforms often test Node.js directly, through a live coding round or a technical screen, rather than just taking a resume's word for it. These questions cover the parts of Node.js that actually come up under that kind of scrutiny: Event Loop & Async I/O, Streams & Buffers and Process & Module Management.
Below are 10 questions split into technical, scenario, and behavioral rounds, each with a full written answer so you can see what a strong response sounds like.
Technical (5)
How does Node.js handle concurrency on a single thread?
Node runs JavaScript on a single thread but delegates I/O operations, like file reads or network requests, to the underlying system via libuv's event loop and a thread pool for certain operations. The main thread never blocks waiting on I/O; it registers a callback and moves on, then the event loop picks up completed operations and runs their callbacks, which is why Node handles many concurrent connections well despite being single-threaded for JS execution.
What's the difference between `require` and `import`, and why can mixing them cause problems?
`require` is CommonJS, resolved synchronously at runtime, while `import` is the ES Modules syntax, resolved and statically analyzed at parse time, which is what enables tree-shaking. Mixing them in the same project can cause issues because CommonJS modules are wrapped and exposed to ESM differently, sometimes losing named exports or requiring `.default`, so the two systems don't interoperate seamlessly without careful configuration.
What's the purpose of streams in Node.js, and when would you use one instead of reading a whole file into memory?
Streams process data in chunks as it arrives instead of loading an entire resource into memory at once, which matters for large files or network payloads where buffering everything upfront would spike memory usage or delay the first byte of output. Piping a large file directly to an HTTP response with `fs.createReadStream().pipe(res)` starts sending data immediately and keeps memory usage roughly constant regardless of file size.
Explain the difference between `process.nextTick()`, `setImmediate()`, and a `Promise` microtask.
`process.nextTick()` callbacks run before the event loop continues to the next phase, even before promise microtasks, making it the highest priority. Promise callbacks run in the microtask queue right after that. `setImmediate()` callbacks run in the check phase of the event loop, after I/O callbacks in the current iteration, so they're the latest of the three to execute relative to the current operation.
How do you handle an uncaught exception in a Node.js process, and why is it risky to just catch and ignore it?
Node emits an `uncaughtException` event on the process object, but the recommended practice is to log it and then shut down the process gracefully rather than continuing to run, since an uncaught exception often means the application is in an unknown, possibly corrupted state. Continuing to serve requests after that point risks silent data corruption or cascading failures that are much harder to debug than a clean restart.
Scenario (3)
An Express API's memory usage climbs steadily over days and eventually crashes the process. How do you investigate?
I'd take heap snapshots at intervals using `--inspect` and Chrome DevTools, or a tool like `clinic.js`, and compare them to see what object type is accumulating. Common causes in a long-running Node process are an in-memory cache with no eviction, event listeners added on every request without being removed, or references held in a closure that never gets garbage collected because something external still points to it.
A downstream API your service calls occasionally times out, and right now those failed requests just hang. How would you fix it?
I'd wrap the outbound call with an explicit timeout, using `AbortController` with `fetch` or the timeout option on whichever HTTP client is in use, so a slow response fails fast instead of hanging indefinitely. I'd also add retry logic with backoff for transient failures, and make sure the timeout duration accounts for the caller's own timeout budget so failures propagate cleanly instead of silently disappearing.
You need to run a CPU-intensive task, like image processing, inside a Node.js server without blocking incoming requests. What's your approach?
Since Node is single-threaded for JS execution, a heavy synchronous computation blocks the event loop and stalls every other request while it runs. I'd offload the work to a `worker_threads` worker or a separate child process, communicating the result back via message passing, so the main event loop stays free to keep handling other requests concurrently.
Behavioral (2)
Tell me about a time you tracked down an event loop blocking issue in production.
A JSON export endpoint was intermittently making the whole service unresponsive for a few seconds at a time. It turned out a synchronous `JSON.stringify` on a very large object was blocking the event loop long enough to delay every other in-flight request. I fixed it by streaming the export in chunks instead of building and serializing the whole object at once, and added a slow-request alert to catch similar blocking calls earlier.
Describe a time you had to decide between using an existing npm package versus writing something custom.
I needed date-range parsing for a reporting feature and found a package that mostly fit, but it pulled in a large dependency tree for a small amount of functionality I actually needed. I wrote a small custom function instead, about 30 lines, since the maintenance burden of a heavy dependency for a narrow use case outweighed the convenience, and it kept the bundle and audit surface smaller.
Knowing the answer and saying it out loud under pressure are different skills.
The Academy has free modules and mock exams to build the second one.
Open roles using Node.js
See all roles →
Full Stack Engineer (Node.js and React)
$80-100
React and Next.js Engineer
$70-90