Skip to content

Node.js Core Interview Questions for MERN Stack

25 Node.js Core questions with answers for mern stack roles — 10 easy, 10 medium, 5 hard.

About Node.js Core

Node.js runs JavaScript on the server using the V8 engine and libuv. This topic explains the event loop phases, non-blocking I/O, streams, buffers, EventEmitter, modules, the thread pool, worker threads and clustering. You will also see how to handle errors, configuration and graceful shutdown, which are common interview themes for backend and full stack roles.

Sheet progressStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

What is Node.js and how does it handle many requests on a single thread?

Save to ▾
Show answer
Node.js is a JavaScript runtime built on the V8 engine and libuv. Your JavaScript runs on one main thread, but I/O such as network calls, file reads and database queries is non-blocking. Node hands that work to the operating system or the libuv thread pool and continues with other requests; callbacks run when results are ready. This makes it efficient for I/O-heavy APIs, but weak for CPU-heavy work.
02

What is the difference between CommonJS and ES modules in Node.js?

Save to ▾
Show answer
CommonJS uses require and module.exports, loads synchronously and is the historic Node default. ES modules use import and export, are statically analysable, support top-level await and enable tree shaking. Node treats .mjs files, or .js files when package.json has type: module, as ESM. Modern Node versions can even require synchronous ES modules, but mixing systems still needs care, so new MERN projects usually pick ESM throughout.
03

What is a Buffer in Node.js?

Save to ▾
Show answer
A Buffer is a fixed-size chunk of raw binary memory allocated outside the V8 heap, used for files, network packets, images and encodings. You create one with Buffer.from('hello') or Buffer.alloc(10) and convert with toString('utf8'), toString('base64') or toString('hex'). Streams deliver data as Buffers by default. Buffer.allocUnsafe is faster but may contain old memory, so it must be filled before use.
04

What is the EventEmitter class and where is it used?

Save to ▾
Show answer
EventEmitter from the node:events module implements the publish-subscribe pattern. You register listeners with on or once and trigger them with emit, passing data. Many core objects extend it, including HTTP servers, streams and process. Always handle the error event, because an emitted error with no listener crashes the process. Remove listeners you no longer need to avoid the MaxListenersExceededWarning and memory leaks.
05

What is the difference between package.json and package-lock.json, and what do ^ and ~ mean?

Save to ▾
Show answer
package.json lists dependencies with version ranges, scripts and metadata. package-lock.json records the exact installed versions of every package, including nested ones, so every machine and CI build gets the same tree. Commit both and use npm ci in pipelines. A caret like ^4.18.2 allows minor and patch updates below 5.0.0; a tilde like ~4.18.2 allows only patch updates below 4.19.0.
06

How do you manage configuration and secrets differently for development and production in Node.js?

Save to ▾
Show answer
Keep config in environment variables, following the twelve-factor approach. Locally, load a .env file with dotenv or Node's built-in --env-file flag, and add .env to .gitignore while committing a .env.example. In production, inject variables through the hosting platform or a secrets manager. Validate all required variables at startup with a schema library like zod so the app fails fast with a clear message.
07

Create a basic HTTP server in Node.js without Express that returns JSON.

Save to ▾
Show answer
The built-in node:http module is enough for simple servers. import http from 'node:http'; const server = http.createServer((req, res) => { if (req.method === 'GET' && req.url === '/health') { res.writeHead(200, { 'Content-Type': 'application/json' }); return res.end(JSON.stringify({ status: 'ok' })); } res.writeHead(404); res.end(); }); server.listen(3000, () => console.log('Listening on 3000')); Express adds routing, middleware and body parsing on top of this.
08

Read a JSON file and write an updated version using fs/promises and async/await.

Save to ▾
Show answer
The promise-based fs API keeps code clean and non-blocking. import { readFile, writeFile } from 'node:fs/promises'; async function addUser(user) { try { const data = JSON.parse(await readFile('users.json', 'utf8')); data.push(user); await writeFile('users.json', JSON.stringify(data, null, 2)); } catch (err) { console.error('Failed to update file', err); throw err; } } Avoid readFileSync inside request handlers because it blocks the event loop.
09

Show how to create and use a custom EventEmitter.

Save to ▾
Show answer
Extend EventEmitter to emit domain events. import { EventEmitter } from 'node:events'; class OrderService extends EventEmitter { place(order) { // save order... this.emit('order:placed', order); } } const orders = new OrderService(); orders.on('order:placed', (o) => sendEmail(o.userEmail)); orders.once('order:placed', () => console.log('first order')); orders.place({ id: 1, userEmail: 'a@b.com' }); Listeners run synchronously in registration order.
10

How do you set up npm scripts for development and production in a Node.js API?

Save to ▾
Show answer
Define scripts in package.json and run them with npm run. "scripts": { "dev": "node --watch --env-file=.env src/server.js", "start": "node src/server.js", "lint": "eslint .", "test": "vitest run" } Modern Node has a built-in --watch flag, so nodemon is optional. npm start and npm test work without the run keyword.
11

What is the difference between process.nextTick, setImmediate and setTimeout(fn, 0)?

Save to ▾
Show answer
process.nextTick queues a callback to run right after the current operation, before Promise microtasks and before the event loop continues. setImmediate runs in the check phase after poll. setTimeout with 0 runs in the timers phase once at least about 1 ms has passed. Overusing nextTick recursively can starve I/O, so setImmediate is the safer way to defer heavy work.
12

What are streams in Node.js and what types exist?

Save to ▾
Show answer
Streams process data in chunks instead of loading it all into memory. The four types are Readable (file read, HTTP request), Writable (file write, HTTP response), Duplex (TCP socket) and Transform (gzip, encryption), which modifies data as it passes. Streams handle backpressure, pausing the source when the destination is slow. pipeline() from node:stream/promises connects them safely and handles errors and cleanup.
13

Your API becomes unresponsive whenever a user uploads an image for resizing. What is happening and how do you fix it?

Save to ▾
Show answer
Resizing is CPU-bound work running on the main thread, so it blocks the event loop and every other request waits. Fix it by moving the work off the main thread: use a worker_threads pool, a native library like sharp that works in the libuv pool, or better, push a job to a queue such as BullMQ with Redis and process it in a separate worker service, then notify the client.
14

Your script crashes with out of memory while reading a 5 GB log file. How would you rewrite it?

Save to ▾
Show answer
fs.readFile loads the whole file into memory, which exceeds the heap. Use a stream instead: fs.createReadStream with readline lets you process one line at a time with for await, keeping memory flat. If you need to transform and write output, connect read, transform and write streams with pipeline so backpressure and errors are handled. Increasing --max-old-space-size only hides the real problem.
15

How do you implement graceful shutdown for a Node.js API during deployments?

Save to ▾
Show answer
Listen for SIGTERM and SIGINT. When received, stop accepting new connections with server.close(), let in-flight requests finish, close database connections with mongoose.connection.close() and other resources, then exit with code 0. Set a timeout, for example 10 seconds, after which you force exit. In Kubernetes or behind a load balancer, also fail the readiness check first so traffic stops reaching the instance.
16

Your Node.js API runs on an 8-core server but CPU monitoring shows only one core busy. What do you do?

Save to ▾
Show answer
A Node process runs JavaScript on a single thread, so one instance uses about one core. Run multiple instances: PM2 in cluster mode with -i max, the cluster module, or several containers behind a load balancer such as Nginx. Because instances do not share memory, move sessions, caches and rate-limit counters to Redis, and make sure the app is stateless so any instance can serve any request.
17

Compress a large file with gzip using streams in Node.js.

Save to ▾
Show answer
pipeline connects streams and handles errors and cleanup. import { createReadStream, createWriteStream } from 'node:fs'; import { createGzip } from 'node:zlib'; import { pipeline } from 'node:stream/promises'; await pipeline( createReadStream('access.log'), createGzip(), createWriteStream('access.log.gz') ); Memory stays low regardless of file size, and backpressure is managed automatically.
18

How do you add a timeout to a fetch call in Node.js?

Save to ▾
Show answer
Node 18 and later ship a global fetch. Use AbortSignal.timeout to cancel slow requests. async function getJSON(url) { try { const res = await fetch(url, { signal: AbortSignal.timeout(5000) }); if (!res.ok) throw new Error(`HTTP ${res.status}`); return await res.json(); } catch (err) { if (err.name === 'TimeoutError') console.error('Request timed out'); throw err; } } Without a timeout, a hung upstream can hold connections open indefinitely.
19

Describe a production issue you handled in a Node.js service.

Save to ▾
Show answer
Situation: our order API started timing out every evening at peak. Task: as the on-call developer I had to restore it. Action: I checked logs and metrics, found event-loop lag spikes, and traced them to a synchronous CSV export running inside a request. I moved the export to a background job and added event-loop lag alerts. Result: p95 latency dropped from 4 seconds to 300 ms and timeouts stopped.
20

How do you plan a Node.js major version upgrade for a project your team maintains?

Save to ▾
Show answer
Situation: our services were on a Node version nearing end of life. Task: I owned the upgrade to the current LTS. Action: I read the changelog for breaking changes, upgraded locally, ran the test suite, fixed deprecated APIs and incompatible native packages, and rolled out to staging, then one production service, watching metrics. Result: all services moved within two sprints with no incidents, and I added an LTS calendar to our planning.
21

Explain the phases of the Node.js event loop.

Save to ▾
Show answer
Each loop iteration goes through phases: timers runs expired setTimeout and setInterval callbacks; pending callbacks runs some deferred system callbacks; poll waits for and runs I/O callbacks; check runs setImmediate callbacks; close callbacks handles events like socket close. Between every callback, Node drains process.nextTick callbacks and then Promise microtasks. Knowing this explains why setImmediate inside an I/O callback always runs before a setTimeout of 0.
22

What is libuv and which operations use the Node.js thread pool?

Save to ▾
Show answer
libuv is the C library that provides Node's event loop and asynchronous I/O. Network I/O uses non-blocking OS mechanisms like epoll or IOCP, so it does not use the pool. The thread pool, four threads by default, handles file system calls, DNS lookup, zlib compression and crypto functions like pbkdf2 and scrypt. Heavy bcrypt or crypto load can saturate it; UV_THREADPOOL_SIZE can increase it.
23

Compare worker_threads, cluster and child_process in Node.js.

Save to ▾
Show answer
cluster forks multiple Node processes that share one server port, used to use all CPU cores for an HTTP app, though PM2 or containers often do this instead. child_process runs a separate program or script, for example ffmpeg, communicating through stdio or IPC. worker_threads run JavaScript in parallel threads inside one process and can share memory through SharedArrayBuffer, best for CPU-heavy tasks like image processing or parsing.
24

How should errors be handled in a Node.js application?

Save to ▾
Show answer
Separate operational errors, like a failed DB connection or invalid input, which you handle and respond to, from programmer errors, like undefined property access, which signal bugs. Use try/catch with async/await, always handle Promise rejections and stream error events. Listen to uncaughtException and unhandledRejection only to log and exit cleanly, then let a process manager restart the app, because state may be corrupted.
25

Memory usage of a production Node.js service keeps rising until it restarts. How do you investigate?

Save to ▾
Show answer
First confirm the trend with monitoring of heapUsed and RSS. Reproduce in staging under load, then take heap snapshots with --inspect and Chrome DevTools, or use --heapsnapshot-signal, and compare snapshots to find growing object types and their retainers. Common causes are unbounded in-memory caches, listeners added per request, global arrays and unclosed timers. Fix the root cause, add a bounded LRU cache, and set alerts.

Frequently asked questions

How important is Node.js Core in MERN Stack interviews?

Node.js runs JavaScript on the server using the V8 engine and libuv. This topic explains the event loop phases, non-blocking I/O, streams, buffers, EventEmitter, modules, the thread pool, worker threads and clustering. You will also see how to handle errors, configuration and graceful shutdown, which are common interview themes for backend and full stack roles.

How should I use the Node.js Core sheet?

Go top to bottom — easy to hard. Answer before opening each answer, tick what you solved and save misses to Last-Minute Revision.