Interview Q&A / Node.js

INTERVIEW Q&A · 68 QUESTIONS

Node.js interview questions

The event loop on the server, streams, modules and building APIs with Express.

  1. How do you handle errors in asynchronous Node.js code, and what is an unhandled promise rejection?

    Use try/catch around await, .catch() on promise chains, and the error-first argument in callbacks. An unhandled rejection is a promise that fails with no handler attached; since Node 15 it crashes the process by default, so every promise needs a catch somewhere.

    IntermediateIn-depth3 min read
  2. What are streams in Node.js and why would you use them for large files?

    A stream processes data in small chunks as it arrives instead of loading everything into memory at once. For a large file, streams keep memory use low and let you start sending data immediately, and pipeline() handles backpressure and errors for you.

    IntermediateIn-depth3 min read
  3. What is the difference between process.nextTick, setImmediate and setTimeout in Node.js?

    process.nextTick runs right after the current operation, before promise callbacks and before the event loop moves on. setImmediate runs in the check phase, right after I/O polling. setTimeout(fn, 0) runs in the timers phase after at least about 1 ms.

    IntermediateIn-depth3 min read
  4. How can CommonJS code load an ES module?

    Use dynamic import(), which works in CommonJS and returns a promise. Plain require of an ES module was not allowed historically; newer Node versions added limited support, so dynamic import is the safe choice.

    IntermediateQuick answer1 min read
  5. How do you read a very large file line by line in Node.js?

    Create a read stream and pass it to readline.createInterface, then loop with for await. Only a small chunk sits in memory at a time, unlike readFile, which loads the whole file.

    IntermediateQuick answer1 min read
  6. How do you send a large file to the browser without loading it all in memory?

    Create a read stream of the file and pipe it into the HTTP response. Set the Content-Type and, if known, Content-Length headers first, and handle stream errors before any bytes are sent.

    IntermediateQuick answer1 min read
  7. How do you version a REST API, and why would you?

    Versioning lets you change the API without breaking existing clients. The common way is a URL prefix such as /api/v1. Other options are a custom header or media type. Avoid breaking changes inside a version.

    IntermediateQuick answer1 min read
  8. How do you write a JSON file in Node.js without risking a half-written file?

    Write the data to a temporary file in the same folder, then rename it over the target. Rename is atomic on the same filesystem, so readers see either the old file or the complete new one.

    IntermediateQuick answer1 min read
  9. How does bcrypt store the salt and what does the cost factor mean?

    The 60-character bcrypt hash contains the algorithm version, the cost, the 22-character salt and the hash itself, so you store one string. The cost is a power of two: each +1 doubles the work.

    IntermediateQuick answer1 min read
  10. How does Express know a middleware is an error handler?

    By its arity: an error-handling middleware takes four arguments (err, req, res, next). It must be registered after the routes, and errors reach it through next(err) or a thrown error in synchronous code.

    IntermediateQuick answer1 min read
  11. How should a REST API return error responses consistently?

    Use one JSON shape for every error with the right HTTP status, a stable machine-readable code, a human message, and optional field details. Never leak stack traces or database errors to clients.

    IntermediateQuick answer1 min read
  12. How would you design pagination for an API endpoint that returns thousands of records?

    Return a slice per request using limit and page (offset) or, for large changing data, a cursor of the last item seen. Cap the maximum limit and return total or next-page information in the response.

    IntermediateQuick answer1 min read
  13. Predict the output: setTimeout, a promise, process.nextTick and plain logs together

    Synchronous code runs first, then process.nextTick callbacks, then promise callbacks (microtasks), then timers. So the order is sync, nextTick, promise, setTimeout.

    IntermediateQuick answer1 min read
  14. Should you use await inside a for loop or Promise.all for independent tasks?

    For independent tasks use Promise.all with map so they run concurrently. await inside a loop runs them one by one, which is right only when each step depends on the last or order and rate limits matter.

    IntermediateQuick answer1 min read
  15. What are peerDependencies in package.json?

    peerDependencies declare packages your library needs but expects the host application to install, so only one shared copy exists. Plugins and UI libraries use them, for example a React component library requiring react.

    IntermediateQuick answer1 min read
  16. What are the main phases of the Node.js event loop?

    Timers, pending callbacks, idle/prepare, poll, check, and close callbacks. Timers run setTimeout callbacks, poll collects I/O, check runs setImmediate, and microtasks are drained between steps.

    IntermediateQuick answer1 min read
  17. What does idempotent mean for HTTP methods, and which methods are idempotent?

    An idempotent request has the same effect on the server whether it is sent once or many times. GET, PUT, DELETE, HEAD and OPTIONS are idempotent; POST is not, and PATCH may not be.

    IntermediateQuick answer1 min read
  18. What is a circular dependency in Node.js and what happens when it occurs?

    A circular dependency is when module A requires B and B requires A. In CommonJS, the second module receives A's partially filled exports at that moment, so values defined later are undefined. Fix it by restructuring.

    IntermediateQuick answer1 min read
  19. What is a refresh token and why use it alongside a short-lived access token?

    The access token is short-lived (minutes) and sent on every request. The refresh token is long-lived, stored safely and used only to get a new access token. A stolen access token then expires quickly, and refresh tokens can be revoked.

    IntermediateQuick answer1 min read
  20. What is backpressure in Node.js streams?

    Backpressure is when a writable cannot consume data as fast as a readable produces it. The writable signals this, and the reader should pause, otherwise memory fills up with unwritten data.

    IntermediateQuick answer1 min read
  21. What is CORS and how do you enable it safely in an Express API?

    CORS is a browser rule that blocks a page from reading responses from a different origin unless the server allows it with headers. In Express, use the cors package with an allow-list of origins, not a wildcard for private APIs.

    IntermediateQuick answer1 min read
  22. What is the difference between session-based authentication and JWT authentication?

    Sessions store user state on the server and give the browser only a session id cookie. JWTs carry signed user claims in the token itself, so the server stores nothing, but revoking a token before it expires is harder.

    IntermediateQuick answer1 min read
  23. What is the difference between stream.pipe and stream.pipeline?

    pipe connects streams but does not forward errors or clean up, so a failure can leave streams open. pipeline connects several streams, destroys all of them on error, and reports the result in one callback or promise.

    IntermediateQuick answer1 min read
  24. What is top-level await and where can you use it in Node.js?

    It lets you use await directly at the top of a file without wrapping it in an async function. It works only in ES modules, and it delays anything that imports that module until the promise settles.

    IntermediateQuick answer1 min read
  25. Where should a browser app store a JWT: localStorage or an httpOnly cookie?

    An httpOnly, Secure, SameSite cookie keeps the token out of reach of JavaScript, so an XSS bug cannot steal it, but you must then handle CSRF. localStorage is simple but readable by any script on the page.

    IntermediateQuick answer1 min read
  26. Write a Transform stream that converts incoming text to uppercase.

    Extend stream.Transform (or pass a transform function), call this.push with the changed chunk, and call the callback when done. Then pipe a readable into it and into a writable.

    IntermediateQuick answerCoding1 min read