Advanced everything in Node.js & Express, page 3

PM2: Zero-Downtime Reloads in Cluster Mode
PM2's reload command updates a clustered Node.js app without downtime by restarting processes one by one. Use this for live deployments. The footgun is using it on a stateful app, which will cause data loss unless state is externalized.

Sticky Sessions: Pinning a User to a Server
Sticky sessions pin a user's requests to a single server in a multi-server setup. This is crucial for stateful apps like Socket.IO, where a user's session lives on one machine.

Socket.IO Adapters: Scaling Beyond One Server
Socket.IO adapters let you scale beyond one server. They use a backend like Redis Pub/Sub to broadcast messages across all your instances, so a user on Server A gets events from Server B. The footgun is assuming this handles everything; you still need a load.

Socket.IO Namespaces: Channels on One Connection
Socket.IO namespaces are virtual channels over a single WebSocket connection, letting you split app logic without multiple connections. Use them for separate areas like /admin or for multi-tenancy.
V8's Garbage Collector: A Performance Pillar
V8's garbage collector is a key to its speed, using a "stop-the-world, generational, accurate" approach to reclaim memory. This runs automatically in Node.js and Chrome, but its pauses can impact performance.

SharedArrayBuffer: True Shared Memory for JS Threads
SharedArrayBuffer is a shared whiteboard for JS threads, letting them access the same memory without slow data copies. It's used for high-performance parallel tasks. The footgun: without Atomics to coordinate, you'll get race conditions and corrupted data.
Nock: Intercept and Mock Node.js HTTP Requests
Nock acts like a fake switchboard for your Node.js app's outgoing HTTP calls, redirecting them to pre-defined responses. This lets you unit test code that relies on external services, making tests fast, deterministic, and offline-capable.
E2E Testing: The Final Check, Not The Whole Strategy
E2E testing is a dress rehearsal for your app, simulating a full user journey. Use it sparingly for critical flows like checkout, as it tests all services together. The footgun is over-reliance: they are slow, brittle, and hard to debug.
Node.js Uncaught Exceptions: Clean Up, Don't Continue
An uncaught exception is a fire alarm for your Node.js app, signaling an unknown state. Use the process.on('uncaughtException') hook for last-resort synchronous cleanup before exiting, not to resume normal operation.
JWT Storage: Cookies (CSRF Risk) vs. Local Storage (XSS Risk)
Storing JWTs means choosing your risk: Cross-Site Request Forgery (CSRF) with cookies, or Cross-Site Scripting (XSS) with local storage. While local storage is simpler, HttpOnly cookies are generally safer as they can't be read by client-side scripts.
CSRF Tokens: Preventing Unwanted State Changes on Your Behalf
CSRF protection prevents a malicious site from forcing a user's browser to submit unwanted requests to your app. It adds a unique token to forms that the server validates. The footgun is failing to protect all state-changing endpoints, not just POST forms.
Passport.js: The Generic OAuth2 Strategy
Passport's generic OAuth2 strategy is a template for social logins, not a plug-and-play solution. Use it to integrate a custom OAuth2 provider. The footgun is using it when a provider-specific strategy (like passport-github2) exists, which handles quirks for…
OAuth 2.0: Delegated Authorization, Not Authentication
Think of OAuth 2.0 as a valet key for your data. It lets a third-party app access specific resources on your behalf without you sharing your password. It's used for "Log in with Google" or letting an app access your photos.
Sequelize Scopes: Reusable Query Shortcuts
Sequelize scopes are named shortcuts for common query conditions, letting you define where or include clauses once and reuse them. Use them to keep code DRY, like an active scope. The footgun: a defaultScope is always on unless you call .unscoped().

Mongoose Population: Linking Documents Across Collections
Mongoose's populate() acts like a client-side JOIN, replacing document IDs with actual documents from other collections. It's ideal for linking related data, like a blog post's author.
Sequelize Transactions: All-or-Nothing Database Writes
A Sequelize transaction is a safety wrapper for database queries, ensuring they all succeed or none do. Use it for multi-step operations like creating a user and profile.
HATEOAS: Let Your API Tell You What's Next
HATEOAS makes an API self-discoverable, like a website where you click links instead of guessing URLs. The server's response includes links for the next possible actions, decoupling the client from hardcoded endpoints.
API Rate Limiting: Protecting Your Express Endpoints
Rate limiting acts as a bouncer for your API, preventing any single user from overwhelming it. It's crucial for public APIs and sensitive endpoints like password resets to block abuse. The default in-memory store won't work across multiple server instances.

Idempotency in REST APIs: Safe to Retry?
An idempotent API request means sending it once or 100 times has the same effect on the server's state. GET, PUT, and DELETE are idempotent, making them safe to retry. POST is not, so retrying can create duplicates.

Express Error Middleware: Your App's Safety Net
Express error middleware is a safety net that intercepts unhandled errors, preventing crashes. It's used to centralize logging and format consistent error responses. The biggest footgun is placement: it must be defined *after* all other routes and middleware.
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