How does Node.js handle concurrent requests with a single thread?
Reported in Skyscanner European engineering loops. Node.js architecture question on libuv, event loop phases, and worker threads.
Interview scenario
Often asked in Skyscanner loops at European offices (London, Berlin, Amsterdam, Paris, Stockholm, Dublin, and remote EU). Prepare a clear spoken answer plus key trade-offs.
Model answer
Try answering aloud first
Cover trade-offs, structure, and a concrete example before revealing the baseline response.
How to frame this at Skyscanner: Connect your answer to measurable impact, clarity of thought, and trade-offs the team cares about. Below is a strong baseline response you can adapt with your own project examples.
Node.js uses an event-driven, non-blocking I/O model. A single main thread runs JavaScript while libuv handles async I/O via thread pool (filesystem, DNS) and OS async mechanisms (epoll, kqueue).
Event loop phases: timers → pending callbacks → idle → poll (I/O) → check (setImmediate) → close callbacks. Long CPU work blocks the loop—defer with worker threads or child processes.
Each connection is cheap compared to thread-per-request servers—great for I/O-heavy APIs, websockets, and proxies. Poor fit for CPU-heavy video encoding without offloading.
Best practices: avoid sync APIs in production, stream large files, use clustering or PM2 for multi-core, and monitor event loop lag. Contrast with traditional Java servlet thread pools.
Discussion
Comments (0)
Share how this question came up in your loop, or add tips for others preparing.
Log in to comment on this question.