The Evolution of Node.js

How JavaScript left the browser and never came back

May 2009
Origins

Ryan Dahl Unveils Node.js

Ryan Dahl presents Node.js at JSConf EU. Built on Chrome's V8 engine. Event-driven, non-blocking I/O. The idea: JavaScript can do server-side work if you stop making it wait for disk and network. "I want to write servers in JavaScript."

2010
Origins

npm and Express

npm (Node Package Manager) ships. The package registry model that changed how JavaScript distributes code. Express.js launches — the web framework that became the default. Socket.io brings real-time to the browser. Heroku adds experimental Node support.

2011
Growth

Windows Support & npm 1.0

Node.js gets Windows support, opening it to a massive audience. npm 1.0 ships. LinkedIn rewrites its mobile app in Node. Uber follows. The enterprise adoption story begins.

2012
Growth

Ryan Dahl Steps Back

Ryan Dahl steps down as lead. Isaac Schlueter (npm creator) takes over. Node v0.8.0 ships. The project begins its transition from one person's vision to a community-driven effort. Hapi framework launches.

2013
Growth

The MEAN Stack Era

MongoDB + Express + Angular + Node becomes the full-stack JavaScript story. Ghost launches as a Node.js blogging platform. Koa.js (by the Express creators) debuts. PayPal builds Kraken. Node hits the mainstream.

Dec 2014
The Fork

io.js Forks Node

Disagreements over governance and pace of development. A group of core contributors fork Node.js into io.js. Goal: faster releases, open governance, ES6 support. The JavaScript community splits in two.

Sep 2015
The Fork

The Reunion — Node.js 4.0

Node.js and io.js merge under the newly formed Node.js Foundation (Linux Foundation). Node.js 4.0 ships — jumping from v0.12 to v4 to reflect io.js versioning. ES6 support lands. The LTS (Long-Term Support) model is born.

2016
Maturation

leftpad and Yarn

The leftpad incident — a developer unpublished 11 characters from npm, breaking thousands of projects. The npm ecosystem's fragility exposed. Yarn launches as an alternative package manager. Node 6 ships with full ES6 support.

2017
Maturation

Mainstream Adoption

8.8 million Node.js online instances. 3 billion npm downloads per week. 1,500+ contributors. 40,000+ GitHub stars. Node 8 ships with async/await support. The year Node went from "interesting" to "industry standard."

2018
Maturation

Node 10 — Worker Threads

Worker threads land — true parallelism in Node.js. N-API stabilizes (native addon ABI stability). llhttp replaces the HTTP parser. Native crypto improvements. V8 updated to 7.4. Async stack traces arrive.

2019
Modern Era

OpenJS Foundation

The Node.js Foundation merges with the JS Foundation to create the OpenJS Foundation. One organization supporting the entire JavaScript ecosystem. npm joins too. Node 12 ships.

Apr 2020
Modern Era

Node 14 — Experimental Permissions

Permission model debuts as --experimental-permission. A philosophical shift: Node acknowledges that "trust everything by default" was a design flaw. ES modules gain stability. V8 8.x. Node 14 becomes LTS.

2021
Modern Era

Corepack & ESM

Corepack ships — built-in manager for npm, yarn, and pnpm. packageManager field in package.json. ES modules become the default for new packages. Fetch API lands experimentally. Node 16 becomes LTS.

Apr 2022
Modern Era

Node 18 — Fetch Stable & Test Runner

Fetch API goes stable. node:test — the built-in test runner — ships experimentally. Single executable applications (SEA) announced. Undici becomes the default HTTP client. Node 18 becomes LTS "Hydrogen."

Apr 2023
Competitive Era

Node 20 — Test Runner Stable

node:test goes stable. Built-in mocking, coverage reporting. Single Executable Applications ship — bundle your Node app into one binary. Permission model picks up traction. Deno 2.0 and Bun 1.0 force Node to innovate faster.

Apr 2024
Competitive Era

Node 22 — Permission Model Stable

Permission model goes stable in v23.5.0 — --permission flag restricts filesystem, child processes, worker threads by default. Native mocking and coverage in test runner. require(esm) lands — require() can load ES modules.

May 2025
Competitive Era

Node 24 — SEA Improved

Single Executable Applications significantly improved. Better native module support, smaller binaries, faster cold starts. Node 24 "Krypton" becomes Active LTS. The runtime now has a real answer to Bun's --compile.

May 2026
Competitive Era

Node 26 — Last Old-Model Release

Node 26 ships as the last release under the old odd/even model. Starting with Node 27, every major becomes LTS. One release per year, calendar-aligned, 36 months of support. Node's release model evolves to match the competition.

Origins (2009–2010)
Growth (2011–2013)
The Fork (2014–2015)
Maturation (2016–2018)
Modern Era (2019–2022)
Competitive Era (2023–2026)

The Story Arc

From Ryan Dahl's laptop in 2009 to the runtime behind most of the web — Node.js's journey is one of community resilience.

The io.js fork could have killed Node. Instead, it forced open governance and made Node stronger. The leftpad incident could have broken trust in npm. Instead, it led to better registry policies. Bun and Deno could have made Node obsolete. Instead, they forced Node to ship built-in test runners, permission models, single executable applications, and a new release cadence.

Node.js's lesson: The ecosystem that survives isn't the one that never breaks — it's the one that breaks and rebuilds stronger. Competition doesn't kill platforms. Complacency does.