Why npm Stopped Running Code Before Yours

npm 12 turns install scripts off by default — and the warning on your screen is newer than anything your assistant was trained on

7 min read

Argued into existence in the Writing Room7 messages · 1 mind changedWhy npm Stopped Running Code Before Yours

You ran 'npm install'. You got a wall of yellow text you didn't ask for, something like 'npm warn ignored scripts' or '1 package had install scripts blocked because they are not covered by allowScripts.' Nothing crashed. The install finished. But something you were expecting to happen — a postinstall step, a native module that's supposed to compile itself — quietly did not.

So you do the normal thing. You paste the warning into Claude or ChatGPT and ask what it means.

Here's the trap this week specifically: if the assistant answering you was trained before this default flipped, its fix is either irrelevant or actively wrong. It might tell you to run a command that errors out. It might tell you to add '--ignore-scripts' to make the warning go away — which does make it go away, and also quietly breaks the exact thing you needed to happen. That's not a hypothetical. I reproduced both failure modes below on a real, freshly installed copy of the version that caused this.

Run 'npm -v' before you ask anyone anything. If it prints 12.0.0 or higher, everything below applies to you exactly as reproduced. If it prints anything below 12.0.0 — 10.x, 11.x, or earlier — none of it does yet — your installs still run 'preinstall', 'install', and 'postinstall' scripts automatically, the old way, and whatever warning sent you here came from a teammate's machine or a CI runner, not your own. One version number tells you which piece you're actually reading.

Let's open the hood

Until this year, npm ran three kinds of scripts automatically during every install, if a package's package.json (the file that lists a package's install scripts) defined them: 'preinstall', 'install', and 'postinstall'. A package that needs to compile a native binary, for instance, uses one of these to do the compiling right after npm drops its files on disk. That's also the easiest way for a malicious package to run arbitrary code on your machine the moment you type 'npm install' — no download, no click, just install.

As of npm 12.0.0, released July 8, 2026 according to the official release notes on the npm/cli GitHub repository, that automatic behavior is off by default. Lifecycle scripts and the implicit native-build step now require you to approve them, package by package, before npm will run them.

I want to show you this happening, not just describe it, because the exact wording matters for what you type next.

The old world, reproduced

I built a tiny package with a postinstall script and installed it with npm 10.9.7, the version this machine had before I touched anything:

npm install ../pkg-with-postinstall --foreground-scripts

> pkg-with-postinstall@1.0.0 postinstall
> node -e "console.log('POSTINSTALL RAN...')"

POSTINSTALL RAN: this line came from a script, not from your code

added 1 package, and audited 3 packages in 352ms

found 0 vulnerabilities

No warning. No approval step. The script just ran, because on 10.9.7 that's what 'install' has always meant.

The new world, reproduced

Then I installed npm 12.0.2 fresh — not upgraded, installed clean into its own folder — and ran the exact same install against the exact same package:

npm install ../pkg-with-postinstall --foreground-scripts

added 1 package, and audited 3 packages in 478ms

found 0 vulnerabilities
npm warn install-scripts 1 package had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts   pkg-with-postinstall@1.0.0 (postinstall: node -e "console.log(...)")
npm warn install-scripts
npm warn install-scripts Run 'npm install-scripts ls' to review, or 'npm install-scripts approve <pkg>' to allow.

Same package, same script, no error — but no 'POSTINSTALL RAN' line either. It just didn't happen. That's the whole story your assistant is answering the wrong version of: the install still succeeds, the warning is not a bug, and the script is sitting there waiting for you to say yes.

One config setting did not move, and this is worth knowing before you touch anything: 'npm config get ignore-scripts' still returns 'false' on npm 12, exactly like it did on 10. That flag was always the blunt "skip everything" switch. What's new is a second, finer gate — 'allowScripts' — sitting on top of it, blocking individual packages until you clear them one at a time.

Doing what the warning actually tells you to do

I followed npm's own instructions, in order, on the same npm 12.0.2 install:

npm install-scripts ls
  1 package has install scripts blocked because they are not covered by allowScripts:
    pkg-with-postinstall@1.0.0 (postinstall: node -e ...)

  Run 'npm install-scripts approve <pkg>' to allow, or 'npm install-scripts deny <pkg>' to deny.

npm install-scripts approve pkg-with-postinstall
  Approved file:../../pkg-with-postinstall:
    added file:../../pkg-with-postinstall

npm rebuild --foreground-scripts
  npm notice run pkg-with-postinstall@1.0.0 postinstall
  npm notice run node -e ...
  POSTINSTALL RAN: this line came from a script, not from your code
  rebuilt dependencies successfully

Three commands, in that order: list what's blocked, approve the one you actually trust, rebuild to run it. Approving also wrote a real entry into my package.json — an 'allowScripts' block recording exactly which package I cleared — which is the part that makes this different from the old world instead of just a slower version of it. Next time your team installs, that decision travels with the repo instead of living in your head.

If you've seen older advice reference 'npm approve-scripts --allow-scripts-pending' instead of 'npm install-scripts ls' — that's not wrong, it's just the old name. npm renamed the command to the 'install-scripts' namespace, and I confirmed on the same 12.0.2 install that 'npm approve-scripts' still works as an alias. Both get you to the same place. That renaming, mid-rollout, is exactly the kind of detail a model trained a few months back has no way to know about.

The two wrong turns

Turn one: '--ignore-scripts' as a blanket fix. This is the advice you're most likely to get, because it's the old answer to "npm is running scripts I don't want." I ran it on npm 12:

npm install ../pkg-with-postinstall --ignore-scripts

added 1 package, and audited 3 packages in 379ms
found 0 vulnerabilities

No warning at all — not because nothing was blocked, but because '--ignore-scripts' skips the review entirely, for every package, silently. If that postinstall script was the thing compiling a native module you actually need, you now have a broken dependency and no error message pointing at why. Worse: I then tried 'npm rebuild', the usual fix people reach for when something silently didn't build, and it still refused to run the script — the block persists even after an ignore-scripts install, so that workaround doesn't save you either. The warning-and-approve flow exists precisely so you don't have to choose between "run everything" and "run nothing." Skipping it throws away the thing npm 12 actually added.

Turn two: 'npm approve-scripts' on a global install. If you hit this warning during 'npm install -g', do not run 'npm approve-scripts'. I tried it:

npm approve-scripts --allow-scripts-pending -g

npm error code EGLOBAL
npm error 'npm approve-scripts' does not work for global installs

Global installs don't have a project package.json to write the approval into, so the command has nothing to write to. On my npm 12.0.2 install, the warning text for a global install already knows this and points somewhere else entirely: 'npm install -g --allow-scripts=pkgname' to allow it once, or 'npm config set allow-scripts=pkgname --location=user' to allow it for every global install going forward. If an assistant hands you the local-install fix for a global-install warning, that's the gap — same underlying feature, different command, and the warning text itself already knows which one you need.

Why this matters

The mechanism here isn't complicated once you've seen it run. What's genuinely hard is that the exact command changed names mid-rollout, and the right fix depends on whether you're installing locally or globally — two branches an assistant trained before this shipped can't distinguish, because it's never seen the newer warning text at all. The npm warning printed on your screen is more current than anything in an assistant's training data, because npm wrote it for the exact version you're running, this week. The failure mode this prevents: typing a fix for last month's npm into this month's terminal, and not knowing why it didn't take.

What to do next

You already ran 'npm -v' at the top of this, so you know whether any of it was yours to fix. If you're going to paste something into an assistant, paste the actual warning text npm printed — not a summary of it in your own words — because the command it's pointing you to is usually sitting right there in the message. On npm 12 and later, for a local install that's almost always going to be 'npm install-scripts ls' to see what's blocked, then 'npm install-scripts approve <pkg>' for the ones you trust, then 'npm rebuild' to run them. For a global install, the local recipe doesn't apply — go back to what the warning itself said: 'npm install -g --allow-scripts=pkgname' to allow it once, or 'npm config set allow-scripts=pkgname --location=user' to allow it for every global install going forward.

Why npm Stopped Running Code Before Yours | Vibecodes