Advanced everything in Node.js & Express, page 2
Solving the N+1 query problem in Sequelize
Define N+1 as one parent query plus one per child, detect it via SQL logging, fix with eager loading using include.
API versioning: URL vs header strategies
Version via URL path (/v1/), a custom or Accept header, or a query param; URL is visible and cache-friendly, headers keep URLs clean but are less discoverable.
Centralized error handling in an Express API
A final four-arg error middleware, an asyncHandler wrapper to funnel promise rejections via next, a custom error class with statusCode, returning uniform JSON.
Conditionally apply middleware by request property
Use express.text({ type: 'application/xml' }) or a guard wrapper that checks req.is() then calls the parser or next().
Write a JWT authentication middleware
Read the header, strip Bearer, jwt.verify with the secret, set req.user and next(), else send 401.
Centralized error-handling middleware
Error middleware takes four args err, req, res, next, is defined last, and runs when next(err) is called or sync errors throw.
Custom API key auth middleware
Read the header from req, on missing or invalid send res.status(401) and return, on valid call next, mount before protected routes.
Modularizing routes with express.Router
Create a Router instance in users.js, attach routes to it, export it, then mount it under a base path with app.use in the main file.
http.Agent and connection pooling
The agent pools and keeps sockets alive, avoiding repeated TCP and TLS handshakes, controlled by keepAlive and maxSockets.
Backpressure in Node.js streams
Backpressure pauses the readable when the writable buffer fills, pipe and pipeline manage it automatically, pipeline also propagates errors and cleans up.
Scaling across cores with cluster and os
Os.cpus gives core count, the primary forks one worker per core, all workers share the listening port, the OS load-balances connections.
Async iterators and for await...of for streaming
Async iterators yield values lazily over time; for await...of consumes them sequentially with backpressure, keeping memory bounded.
Promise.all vs Promise.allSettled
All rejects on the first failure; allSettled always fulfills with a status/value or reason per input. Use allSettled when partial success is acceptable.
Bounded concurrency for many async requests
Chunk the array and await Promise.all per chunk, or run a fixed worker pool pulling from a shared index; cap in-flight requests.
Monorepo workspaces vs private npm packages
Workspaces give atomic cross-service changes and instant local linking but couple release cadence; private packages give versioned isolation but add publish overhead and version drift.
Diamond dependencies and nested node_modules
Npm hoists one version to the top and nests the conflicting version under the dependent package; both coexist on disk.
Circular dependencies in CommonJS modules
When A requires B which requires A, the cache returns A's partial exports; fields defined later are undefined at that moment.
Node.js DNS: lookup vs. resolve
Node.js splits DNS into two paths: dns.lookup uses getaddrinfo for IPs, while the dns.resolve family fetches records like MX or TXT. Use lookup for connections and the resolve family for service discovery.

CI/CD Pipelines for Node.js Applications
A CI/CD pipeline is an automated assembly line for Node.js code, installing dependencies, running tests, and packaging your app for deployment. This is standard for any professional project, but a common footgun is not caching dependencies, leading to slow…

Docker Compose for Multi-Container Apps
Docker Compose is a conductor for your containers. Instead of running each service manually, you define your app and its database in one YAML file and launch them together. This is standard for local Node.js/Postgres development.
We are hiring for this. Every open role lists the topics its interview covers, so you can prepare for the real thing rather than guessing.
See open roles