All posts
Engineering··3 min read

Node in 2015: what we believed, and what actually lasted

Looking back at Node.js in 2015 — callbacks, the io.js split, and which of that year's certainties are still in my projects a decade later.

Numan HussainNuman HussainEntrepreneur · Developer · Team Lead
Node in 2015: what we believed, and what actually lasted

This is a look back, written in 2026. I was taking Node work on Elance at the time, mostly APIs for people who had been quoted twice as much for the same thing in PHP.

Two things happened to Node in 2015, and only one of them got the attention.

The split that got the headlines

io.js had forked away from Node the previous December, largely over governance: releases were slow, V8 was old, and the people doing the work had no say in the project's direction. In September 2015 the two merged back as Node 4.0 under the Node.js Foundation, and the version number jumped from 0.12 to 4 to absorb io.js's numbering.

At the time this felt like the whole story. It wasn't. The fork mattered because of what came back with it: a release schedule you could plan around, and a modern V8, which is what actually made the next five years possible.

The thing that mattered more

Node 4 shipped with enough ES6 to change how the code looked. Arrow functions, let and const, template strings, classes, promises in the language rather than a library. If you had spent the previous two years nesting callbacks, this was the year the nesting started to unwind.

// 2014, and this was the good version
fs.readFile(path, function (err, data) {
  if (err) return done(err);
  parse(data, function (err, parsed) {
    if (err) return done(err);
    save(parsed, done);
  });
});

Everyone had a library for this. Async, Q, Bluebird, and a dozen homegrown helpers that each team swore by. Within three years all of them were replaced by two keywords. That is the pattern worth noticing: the language absorbed the thing the ecosystem had been patching around.

What I believed in 2015 that turned out to be wrong

That the callback style was a permanent cost of using Node, and the right answer was better discipline about it. It wasn't. Waiting was the right answer.

That npm's tiny-module culture was harmless. The left-pad incident was five months away, and the lesson — that a dependency is a relationship with a stranger, not a free lunch — took years to sink in properly.

That server-rendered pages were on the way out. They were not. They came back, and the argument we are having now about server components is the same argument with better tools.

What lasted

Streams. Still the clearest idea in the standard library, still the thing most people skip. Small processes that do one job. The convention of a start script and environment variables, which is why a Node app from 2015 still deploys today with barely any ceremony.

And the habit of reading the changelog before upgrading, which I learned the hard way that year.

If you are choosing a runtime now, the 2015 lesson still applies: prefer the thing with a boring release schedule and people who are paid to maintain it. Excitement is not a maintenance plan.

Why this matters to a client, not just a developer

Clients rarely ask what runtime a thing is built on. They ask whether it will still work in three years, and whether someone else can pick it up. The projects I built in 2015 that are still running are the ones that took the boring options: a supported release, few dependencies, and no cleverness that needed the original author present to explain.

That is the whole argument for the stack I use today, and it was formed in the year everyone was arguing about a fork.

Keep reading