Blog / left-pad and the Fragility of Your Dependency Graph
npm dependencies supply-chain javascript

left-pad and the Fragility of Your Dependency Graph

Eleven lines of JavaScript vanished from npm last week and broke builds worldwide — what left-pad teaches about dependencies, pinning and pipelines.
The CompleteStatus Team · · 6 min read
left-pad and the Fragility of Your Dependency Graph
Want this checked continuously?
CompleteStatus grades your headers, SSL and email security 24/7 — free, commercial use allowed.
Monitor your site free

Last Tuesday, eleven lines of JavaScript disappeared from the internet and thousands of builds around the world stopped dead. Babel wouldn't install. React Native projects wouldn't build. Continuous integration pipelines at companies that had never heard of the package in question lit up red, more or less simultaneously, for hours.

The package was called left-pad. Its job: pad the left side of a string. If you shipped JavaScript last week, there's a decent chance your build depended on it and you found out the hard way. The incident is equal parts comedy and warning shot — and the warning deserves more attention than the comedy is getting.

What actually happened

The short version: a developer named Azer Koçulu maintained a few hundred small open-source packages on npm, among them a messaging library called kik. The company Kik wanted the name, npm sided with the company after a trademark dispute, and Koçulu — objecting to the decision — unpublished all of his packages from the registry. Roughly 273 modules vanished at once.

Most were obscure. One was not. left-pad — those eleven lines — sat deep in the dependency graphs of some of the most-installed packages in the JavaScript ecosystem, including Babel, the compiler a huge share of modern JavaScript projects build with. When left-pad ceased to exist, every fresh npm install that transitively needed it failed. Developers who had never typed the words "left-pad" watched their deploys die with a 404 from the registry.

npm restored the package within hours — an unprecedented "un-unpublish" — and has since announced it is changing its unpublish policy so that a single click can't vaporize a load-bearing module again. Good. But the fix addresses one trigger, not the underlying condition.

Eleven lines

For the record, here is approximately the entire package that broke the internet:

function leftpad(str, len, ch) {
  str = String(str);
  var i = -1;
  if (!ch && ch !== 0) ch = ' ';
  len = len - str.length;
  while (++i < len) {
    str = ch + str;
  }
  return str;
}

That's it. No algorithmic subtlety, nothing you couldn't rewrite in the time it takes to read this paragraph. And yet its absence halted build pipelines at serious companies — because nobody chooses their transitive dependencies. You choose ten packages; they choose a thousand for you.

Lesson one: know your dependency graph

The uncomfortable question left-pad poses: could you list what your build actually depends on? Not your package.json — the whole graph. A typical modern JavaScript project pulls in hundreds of transitive packages, each one maintained by a stranger, each one a potential left-pad.

You don't need to audit every line. You do need to know the shape of your exposure:

  • Run npm ls occasionally and actually look at the output. The depth and breadth usually surprises people.
  • Question tiny dependencies. A one-function package trades a trivial amount of typing for a permanent external liability. left-pad, isarray, and friends are lines of code wearing the costume of infrastructure.
  • Prefer fewer, better-maintained packages over a constellation of micro-modules. Every entry in the graph is a party that can break your build — by unpublishing, by pushing a bad release, by being compromised.

This isn't an argument against open source or against npm — the ecosystem's productivity is real. It's an argument for treating dependencies as what they are: code you now operate, written by someone with no obligations to you.

Lesson two: pin and vendor — a 404 shouldn't stop a deploy

The second failure last Tuesday was architectural: thousands of build pipelines were configured such that the npm registry being unable to serve one file meant nothing could ship. That's an availability dependency on a third party, taken on silently, with no fallback.

Concrete defenses, in escalating order of effort:

  • Pin exact versions. Semver ranges (^4.2.0) mean every install can resolve differently. npm shrinkwrap locks the entire tree — every transitive package at an exact version — so builds are at least reproducible:
npm shrinkwrap
git add npm-shrinkwrap.json
  • Cache or mirror the registry. A local npm mirror or caching proxy (Sinopia is a popular self-hosted option) means packages you've installed once remain installable even if the registry — or one package on it — goes away.
  • Vendor what you can't afford to lose. For genuinely critical dependencies, checking them into your repository or an internal registry is unfashionable but bulletproof. Your deploy should depend on your infrastructure, not on the continued goodwill of every maintainer in your graph.

Shrinkwrap alone would not have fully saved you last week — a pinned version of a package that no longer exists still 404s — which is exactly why the caching and vendoring layers matter.

Lesson three: your build pipeline is production infrastructure

Here's the reframe left-pad should trigger: if a failure in a system prevents you from shipping, that system is production. The npm registry, your CI server, your git host, your artifact storage — an outage in any of them doesn't take your site down, but it takes your ability to fix your site down. The worst time to discover your deploy pipeline is broken is mid-incident, when you're trying to push the fix.

Yet most teams monitor their website obsessively and their pipeline not at all. Builds fail silently into a dashboard nobody has open; a broken nightly deploy goes unnoticed until someone asks why Friday's feature isn't live.

Treat the pipeline like the production system it is: it should have checks, and its failures should page a human.

Monitoring the machinery, not just the site

CompleteStatus can watch this layer alongside your public site. Point an HTTP monitor at your CI server, your internal registry mirror, and your staging environment — the same external checks, keyword assertions and instant alerts you'd put on production, aimed at the machinery that keeps production shippable. When the next left-pad happens (and something shaped like it will), you'll know your pipeline is failing from an alert at 9:04, not from a developer's confused Slack message at 11:30.

Create a free account and put monitors on the systems you deploy with, not just the ones you deploy to. Eleven lines of code took down the JavaScript world for an afternoon — the least we can all do is find out promptly next time.

Stop checking by hand

CompleteStatus runs these exact checks around the clock — uptime, SSL, DNS, security headers and SPF/DKIM/DMARC — and alerts you the moment something changes. One dashboard, one bill.
Start free Run a free check
Uptime is table stakes. We watch the rest — security headers, email authentication, certs and DNS, with the fix attached.
Start free
Company
© 2026 CompleteStatus. All rights reserved. CompleteStatus — operated in the United States · support@completestatus.com