What does non-blocking I/O mean in Node.js?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
I/O calls return immediately instead of pausing execution; completion arrives via callbacks/promises/events. One thread can thus juggle thousands of concurrent connections because it never sits idle waiting for disk or network.
Detailed explanation
Blocking I/O ties a thread to each operation: read a file, wait 50ms doing nothing, continue. Non-blocking APIs hand work to the OS/thread pool and register a continuation, freeing the main thread to serve other requests meanwhile — throughput scales with concurrency rather than thread count. The tradeoff is discipline: any long synchronous operation on the main thread negates everything (fs.readFileSync in a request handler stalls ALL clients). That's why CPU-bound tasks go to worker_threads or child processes, and why sync methods exist only for startup-time scripts. Contrast with thread-per-request servers (Java/PHP classic models): they parallelize compute better but burn memory per connection; Node excels at I/O-bound workloads — APIs, proxies, realtime apps — where most time is spent waiting.
Example
// ❌ blocks the entire server while reading:
app.get('/sync', (_req, res) => {
const data = fs.readFileSync('/tmp/huge.log', 'utf8');
res.send(data.length);
});
// ✅ yields to other requests:
app.get('/async', async (_req, res) => {
const data = await fs.promises.readFile('/tmp/huge.log', 'utf8');
res.send(data.length);
});Interview tip
Define it as 'never wait idly', then immediately contrast with the blocking example — showing you know what breaks the model matters more than praising it.
Common mistakes
- Equating non-blocking with faster raw execution.
- Not knowing sync variants block all requests.