Feb 17, 2026 · 9 min read

Node.js Interview Questions: 20 Must-Know Topics for 2026

Preparing for a Node.js backend interview? These 20 questions cover everything from the event loop to security and scaling — straight from real interviews in 2026. Each comes with a detailed answer and practical tips.

Node.jsJavaScriptBackendExpressInterview

⚡ Event Loop & Async

1. Explain the Node.js event loop and its phases.

The event loop is what allows Node.js to perform non-blocking I/O despite being single-threaded. It cycles through phases: timers (setTimeout/setInterval callbacks), pending callbacks (I/O callbacks deferred to next iteration), idle/prepare (internal), poll (retrieve new I/O events), check (setImmediate callbacks), and close callbacks (e.g., socket.on('close')).

💡 Tip: Draw the phases on a whiteboard if asked. Interviewers love visual explanations. Mention that process.nextTick() runs between phases, before microtasks.

2. What's the difference between callbacks, Promises, and async/await?

Callbacks are the original async pattern — a function passed as an argument, called when the operation completes. They lead to "callback hell" with deep nesting. Promises represent a future value with .then()/.catch() chaining, solving nesting. async/await is syntactic sugar over Promises — it makes async code look synchronous and is the standard in modern Node.js.

💡 Tip: Show that you understand error handling differs: callbacks use error-first pattern (err, data), Promises use .catch(), async/await uses try/catch.

3. What is the difference between setImmediate() and process.nextTick()?

process.nextTick() fires immediately after the current operation, before the event loop continues — it's a microtask. setImmediate() fires in the check phase of the next event loop iteration. Overusing nextTick can starve the event loop since it always runs first.

💡 Tip: Mention that queueMicrotask() is the standard alternative to process.nextTick() in modern Node.js.

📦 Core Modules

4. How do Streams work in Node.js and why are they important?

Streams process data piece by piece without loading everything into memory. There are four types: Readable (e.g., fs.createReadStream), Writable (e.g., fs.createWriteStream), Duplex (read + write, e.g., TCP socket), and Transform (modify data in transit, e.g., zlib compression). They're essential for handling large files, video, or real-time data.

💡 Tip: Give a practical example — "Streaming a 2GB file uses ~MB of RAM vs loading it all at once."

5. What's the difference between Buffer and String in Node.js?

A Buffer is a fixed-size chunk of raw binary data outside the V8 heap. A String is a UTF-16 encoded JavaScript object. Buffers are used for binary protocols, file I/O, and network communication. Converting between them requires specifying encoding (utf8, base64, hex, etc.).

💡 Tip: Mention Buffer.alloc() vs Buffer.allocUnsafe() — the latter is faster but may contain old memory data.

6. How would you read a large file efficiently in Node.js?

Use fs.createReadStream() instead of fs.readFile(). The stream approach reads data in chunks (default 64KB), keeping memory usage constant regardless of file size. Pipe it to a writable stream or process chunks in the 'data' event handler.

💡 Tip: For line-by-line reading, mention the built-in readline module or the for await...of syntax with streams.

🚀 Express & Fastify

7. What is middleware in Express and how does it work?

Middleware functions have access to req, res, and next. They execute sequentially in the order they're defined. Each can modify the request/response, end the cycle, or call next() to pass control. Types include application-level, router-level, error-handling (4 params), built-in (express.json()), and third-party (cors, helmet).

💡 Tip: Mention that order matters — auth middleware should come before protected routes, and error handlers must be defined last.

8. How do you handle errors properly in Express?

Use an error-handling middleware with 4 parameters: (err, req, res, next). Wrap async route handlers with try/catch or use a wrapper function like asyncHandler. In Express 5+, async errors are automatically caught. Always return proper HTTP status codes and structured JSON error responses.

💡 Tip: Mention centralized error handling — one middleware that logs, formats, and responds — instead of try/catch in every route.

9. Express vs Fastify — when would you choose one over the other?

Express: massive ecosystem, battle-tested, simple API, huge community. Fastify: ~2-3x faster, built-in schema validation with JSON Schema, TypeScript-first, plugin architecture with encapsulation. Choose Fastify for new high-performance APIs; Express for projects needing maximum ecosystem compatibility.

💡 Tip: If you mention Fastify, be ready to explain its plugin system and how schema-based serialization boosts performance.

🗄️ Database Integration

10. How do you connect Node.js to MongoDB and handle schemas?

Use Mongoose as an ODM — it provides schema definitions, validation, middleware (pre/post hooks), and query building on top of the native driver. Define schemas with types, required fields, defaults, and custom validators. Use connection pooling for production.

💡 Tip: Mention Mongoose's lean() for read-heavy queries — it returns plain objects instead of Mongoose documents, significantly improving performance.

11. How do you work with PostgreSQL in Node.js?

Options include the low-level pg driver, query builders like Knex.js, or full ORMs like Prisma and Drizzle. Prisma offers type-safe queries and auto-generated migrations. Always use connection pooling, parameterized queries (to prevent SQL injection), and transactions for multi-step operations.

💡 Tip: In 2026, Prisma and Drizzle are the most popular choices. Know the tradeoffs — Prisma has a learning curve but excellent DX; Drizzle is SQL-like and lightweight.

12. What are database transactions and how do you implement them in Node.js?

Transactions ensure that a group of operations either all succeed or all fail (ACID). In Prisma: prisma.$transaction([...]). In Knex: knex.transaction(async trx => {...}). In MongoDB: use sessions with startSession() and withTransaction() (requires replica set).

💡 Tip: Always handle transaction rollback in catch blocks. Mention that MongoDB transactions require a replica set, which catches many juniors off guard.

🔒 Security

13. How do you prevent SQL injection in Node.js?

Always use parameterized queries — never concatenate user input into SQL strings. ORMs like Prisma and Drizzle handle this automatically. With raw pg, use $1, $2 placeholders. Also validate and sanitize input at the API boundary using libraries like zod or joi.

💡 Tip: Even with an ORM, validate inputs. Defense in depth — never rely on a single layer of protection.

14. How do you implement authentication and authorization in a Node.js API?

Authentication: verify identity via JWT tokens, session cookies, or OAuth2. Use bcrypt for password hashing. Authorization: role-based (RBAC) or attribute-based (ABAC) access control in middleware. Store JWTs in httpOnly cookies, use short expiry with refresh tokens, and always validate on the server side.

💡 Tip: Never store JWTs in localStorage (XSS vulnerable). Mention helmet for security headers and cors for cross-origin configuration.

15. How do you protect a Node.js app from XSS and CSRF attacks?

XSS: sanitize user input, escape output, set Content-Security-Policy headers, use helmet. Never use innerHTML with untrusted data. CSRF: use anti-CSRF tokens (e.g., csurf middleware), SameSite cookie attribute, and verify the Origin/Referer header. For APIs with JWT auth, CSRF is less relevant since there are no cookies.

💡 Tip: Explain the difference — XSS injects scripts into the page, CSRF tricks the user's browser into making unwanted requests.

📈 Performance & Scaling

16. How does the Cluster module work and when would you use it?

The cluster module forks multiple worker processes that share the same server port. The master process distributes incoming connections (round-robin on Linux). Each worker runs on a separate CPU core, letting you utilize all cores. Use it for CPU-bound workloads or to improve throughput on multi-core servers.

💡 Tip: In production, prefer PM2 which handles clustering, auto-restart, and load balancing out of the box. Mention that worker_threads is the alternative for CPU tasks without separate processes.

17. What are Worker Threads and how do they differ from child processes?

Worker Threads run JavaScript in parallel threads within the same process — they share memory via SharedArrayBuffer and communicate via message passing. Child processes (child_process) spawn separate OS processes with isolated memory. Workers are lighter and faster for CPU-intensive JS tasks; child processes are better for running external commands or isolating untrusted code.

💡 Tip: Use worker threads for tasks like image processing, encryption, or heavy computation. Don't use them for I/O — the event loop already handles that efficiently.

18. What caching strategies work well with Node.js?

In-memory: node-cache or a simple Map for single-instance apps. Redis: distributed cache, shared across instances, supports TTL, pub/sub, and data structures. HTTP caching: use Cache-Control, ETag, and conditional requests. CDN caching for static assets. Cache at the right layer — database query results, API responses, or computed values.

💡 Tip: Always discuss cache invalidation — it's "one of the two hard things in CS." Mention TTL-based expiry, event-driven invalidation, and cache-aside pattern.

🧪 Testing

19. How do you structure tests in a Node.js application?

Follow the testing pyramid: many unit tests (fast, isolated), fewer integration tests (test modules together), and minimal E2E tests (slow, brittle). Use Jest or Node.js built-in test runner for unit tests, Supertest for HTTP endpoint testing, and tools like Playwright for E2E. Organize tests next to source files or in a __tests__ directory.

💡 Tip: Mention the built-in node:test module (stable since Node 20) — it shows you're up to date with the ecosystem.

20. How do you test APIs and handle mocking in Node.js?

Use Supertest to make HTTP requests against your Express/Fastify app without starting a real server. Mock external dependencies (databases, third-party APIs) with Jest's jest.mock() or libraries like nock for HTTP mocking. For database tests, use an in-memory database or Docker containers with testcontainers.

💡 Tip: Discuss the tradeoff — mocking is fast but can drift from reality. Integration tests with real databases catch more bugs but are slower. A good test suite uses both.

Practice Node.js interview questions with AI

Our Telegram bot simulates real Node.js technical interviews with adaptive difficulty. Get instant feedback, code review, and detailed reports.

🚀 Start Free Practice

Free · 5 interviews at no cost