It was 2012 and I was buried up to my ears in Linux servers, babysitting LAMP stacks that crawled under load. A colleague dropped a benchmark on my desk: a Node.js server handling 10,000 concurrent connections with a single process consuming less memory than Apache under 500. I read it three times. I was sure it was wrong. It wasn't wrong.
I didn't adopt it then — I stayed in my world of infrastructure and Java. But the seed was planted. When I made my definitive pivot to software development in 2021, Node was everywhere. And when I truly understood it — not just how to use it but why it works the way it does — everything clicked. I finally got why it had made so much noise.
This is post #9 in the Awesome Curated: The Tools series, where I dig into tools that pass the filter of our automated curation system. Node.js came up through Sindre Sorhus's awesome-nodejs list — which is basically a universe unto itself — and crossed with a signal in 4 independent awesome lists. That doesn't happen by accident.
What it does
Node.js is a JavaScript runtime built on Chrome's V8 engine, but that's the boring technical description. What makes it special is the non-blocking event loop. In a traditional web server, every incoming request waits: waits for the database to respond, waits for the disk to read a file, waits for the network to return something. While it waits, that thread is blocked — sitting there doing absolutely nothing useful. Multiply that by thousands of connections and you understand why you needed 64GB of RAM just to run a decent server.
Node flips the model. When you kick off an I/O operation, Node registers a callback and moves on. When the disk finishes reading, when the DB responds, when the socket has data — Node knows, and executes what comes next. A single thread managing thousands of in-flight operations simultaneously. It's not magic, it's a different mental model.
// The traditional model (blocking): you wait at every step
// The Node model: you register what you want to happen WHEN something is ready
const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
// This does NOT block the event loop
// Node keeps handling other requests while the disk reads
fs.readFile('./data.json', 'utf8', (err, data) => {
if (err) {
res.writeHead(500);
res.end('Something blew up');
return;
}
// Only now do we respond, when the data is actually available
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(data);
});
});
server.listen(3000, () => {
console.log('Listening on port 3000');
});Modern async/await syntax makes this a lot more readable today:
const fs = require('fs').promises;
const http = require('http');
const server = http.createServer(async (req, res) => {
try {
// Await doesn't block the event loop — it releases the thread while it waits
// Other requests keep getting processed in parallel
const data = await fs.readFile('./data.json', 'utf8');
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(data);
} catch (err) {
res.writeHead(500);
res.end(JSON.stringify({ error: 'Could not read the file' }));
}
});
server.listen(3000);The npm ecosystem is a whole other beast. Over 2 million packages. It's simultaneously an absurd superpower and a security nightmare vector (left-pad, event-stream, the ghosts of the past). But the point is: for almost anything you need, there's a library. You can find the official repository here and Sindre Sorhus's awesome-nodejs here — that second URL is practically a map of the entire ecosystem.
Why it's on the list
Four independent awesome lists pointing at Node.js is community consensus, not hype. And it makes sense: Node solved a real problem that backend development had pre-2009 — the C10K problem, the difficulty of handling 10,000 concurrent connections with traditional servers. Ryan Dahl didn't invent the event loop, but he took an idea that already existed in Nginx and put it in the hands of JavaScript developers, who were already tens of millions strong.
The most important unlock was unifying the language. Before Node, if you were a web dev, you knew JavaScript in the browser and something else (PHP, Ruby, Java) on the server. With Node, same language, same paradigms, same team. That had an enormous organizational impact that you can still feel today in the job market.
Compared to contemporary alternatives: Go wins on raw performance and simplicity of its concurrency model. Python with FastAPI or Django is more readable for many use cases. Java with Spring Boot — my current world — has enterprise maturity and tooling that Node is still building toward. But none of them have the npm ecosystem, none of them have such a low barrier to entry for someone who already knows JavaScript, and none of them moved the developer tooling market as fast — Webpack, Babel, ESLint, Prettier, they all run on Node.
When NOT to use it
If you've got CPU-bound workloads — image processing, heavy cryptography, machine learning, compilation — Node will let you down. The event loop is brilliant for concurrent I/O, but the single thread becomes a bottleneck the moment there's serious computation involved. Worker Threads mitigate this, but at that point you're fighting against the runtime's own design. For those cases, Python with multiprocessing, Go, or Java are more natural fits.
Memory leaks are more frequent and harder to debug than in compiled languages. V8's garbage collector is good, but if you don't deeply understand the model of closures and circular references, you'll watch processes grow in memory without stopping until they explode in production at 3am. I'm speaking from personal experience. Also: if your team doesn't have solid experience with async programming, callback hell and the subtle bugs of async/await can produce code that's genuinely painful to maintain. In those cases, a more opinionated framework like Spring Boot or Django might be healthier in the long run.
Closing thoughts
Node.js is one of those tools that permanently changed the ecosystem. Not because it's perfect — it isn't — but because it arrived at exactly the right moment with exactly the right idea, and pulled millions of developers along with it. Thirty years of watching technology come and go taught me to tell the difference between hype that fades and real change. Node is the latter.
If this post was useful, the Awesome Curated: The Tools series has 8 more posts where I analyze tools with the same lens. From cryptography with Themis to network monitoring with Sniffnet — each one passed the same curation filter before landing here. The next one will too.
Related Articles
pnpm vs npm vs yarn vs bun: The Real Comparison Nobody Gives You in 2025
I used all four in real projects. One wrecked a monorepo at 3am. Another saved my ass in production. Here's the unfiltered truth about every major package manager in 2025.
Spring Boot Actuator: What to Expose, What to Hide, and What to Check Before Adding Endpoints
Actuator isn't the problem. The problem is enabling it without a clear exposure policy. A pragmatic guide to using it as an operational tool without turning it into unnecessary public attack surface.
Spring Boot Actuator: What to Expose, What to Hide, and What to Check Before Adding Endpoints
Actuator isn't the problem. Enabling it without a clear exposure policy is. A practical guide to using it as an operational tool without turning it into unnecessary public attack surface.
Comments (0)
What do you think of this?
Drop your comment in 10 seconds.
We only use your login to show your name and avatar. No spam.