Node.js95 min total · 14 parts
Node.js Fundamentals: The Runtime, the Event Loop, and Building Real APIs
Part 14 of 14 · ~3 min
Common Mistakes Worth Remembering
- "Single JS thread" ≠ "can't do concurrency" — the two claims sound related and aren't: I/O concurrency is Node's strong suit, full stop; the actual constraint is that your own JavaScript never executes two statements in parallel, no matter how much I/O is in flight around it.
- Let one synchronous, CPU-heavy line run inside a request handler and it doesn't just slow down its own caller — the whole process stalls, and every other request
billhookis holding freezes along with it, whether or not it has anything to do with the slow one. process.nextTickisn't a Promise microtask wearing a different name — it jumps ahead of the microtask queue every single time, and a runaway chain of it locks out pending Promises even more thoroughly than a runaway microtask chain would on its own.- Kicking off an async call and never
await-ing or.catch()-ing it, on the hope that a failure somewhere inside will surface on its own — it won't, and depending on the Node version, the whole process may pay for that assumption. - A
.jsfile's module system was never decided by anything written inside that file — it's the nearestpackage.json's"type"field, full stop, and forgetting that is howrequire()failures on perfectly valid ESM packages catch people off guard. - Reaching for
fs.readFileon something that could be large, when a stream would deliver the same data incrementally without ever holding the whole thing in memory at once. - Expecting a
.envfile to just work — Node has no built-in loader for it,dotenv(or a native--env-fileflag) has to actually run, and it has to run before whatever code is depending on the values it sets. - Handling a programmer error the same way as an operational one — an actual bug swallowed and shrugged off can leave the rest of the process running against state that bug already corrupted, which a routine bad request never does.
- Spinning up a fresh database connection for every request instead of pooling them, which is fine right up until real concurrent traffic exhausts the database's own connection ceiling.
- Shipping with a bare
node server.jsand nothing managing it — one uncaught exception and the whole service is down with nothing positioned to bring it back. - Never wiring up a signal handler at all, or wiring up only
SIGTERMand forgettingSIGINT— every deploy or scale-down then drops whatever was mid-flight at that exact moment, and nobody finds out until someone asks where a request went.
One more, because it's worth confirming the mental model actually transfers rather than just describing billhook's own bugs: months later, Devon writes a one-off script in a scripts/ folder to backfill some historical order records, reaches for that same ESM-only ID-generator package, and hits ERR_REQUIRE_ESM all over again — different file, different folder, no webhook code anywhere nearby, same mechanism. Recognizing a bug instantly in a completely unrelated script, several chapters removed from where it was first explained, is the actual sign the model stuck — not just memorizing that one line in orders.js.
Two threads worth pulling on somewhere else, if this one left something dangling. billhook's event loop is running the exact mechanism laid out in the browser-side event loop piece — same two-tier idea, just wired up here to real sockets and files instead of clicks and fetches, and organized into phases where the browser gets away with a single queue. And the four-argument error handler threading through every Express example above isn't an Express quirk either — it's one instance of a pipeline shape that shows up, differently dressed, in Middleware Pipelines Compared. Everything billhook does in this reference — the nextTick ordering, the raw-body signature check, the streaming upload — is sitting in the code lab as code you can actually run, not just read.
Continue learning
- Interview & Career PrepThe Non-Technical Half of the Interview: Behavioral Questions, the STAR Method, and What Recruiters Are Actually Scoring
- AI & LLM EngineeringAI & LLM Engineering Fundamentals: Prompting, RAG, Embeddings, and Function Calling
- TypeScriptTypeScript Fundamentals: Types, Interfaces, Generics, and Why It Catches Bugs Before Runtime