
npm v12 is estimated to ship in July 2026. It changes three npm install behaviors from automatic to opt-in, all aimed at closing supply-chain attack vectors. If you run npm install today without preparing, scripts will silently stop running, and Git or remote URL dependencies will stop resolving. Here is what breaks and exactly what to type before July.
What changes in npm v12
Each of these changes turns an npm install behavior that runs automatically today into one you explicitly opt into:
--allow-file and --allow-directory are not changing their defaults in v12.
You can test all three behaviors today using npm 11.16.0, which shows warnings for anything that would break.
Install scripts are now opt-in
npm install will no longer execute preinstall, install, or postinstall scripts from dependencies unless they are explicitly allowed in your project. This also covers native node-gyp builds. A package with a binding.gyp and no explicit install script still gets blocked, because npm runs an implicit node-gyp rebuild for it. prepare scripts from git, file, and link dependencies are blocked the same way.
The v12 default is soft. An install script you haven't approved gets skipped with a warning, and the install still succeeds. --strict-allow-scripts is a separate option that turns the skip into a hard error. Don't enable it locally until your allowlist is fully set up.
How to migrate your existing project
The fastest path: allow everything currently in your tree first, then tighten later.
# Upgrade npm to get warnings
npm install -g npm@latest
# Run your normal install — warnings show what will be blocked
npm install
# See the full list of packages with unapproved scripts (read-only)
npm approve-scripts --allow-scripts-pending
# Approve everything currently in your tree
npm approve-scripts --all
# Commit the allowlist
git add package.json && git commit -m "chore: snapshot npm v12 install-script allowlist"
This protects you against new, unexpected scripts immediately, and you can use npm deny-scripts afterward to remove anything you don't need.
By default, npm approve-scripts <pkg> pins approval to the installed version (pkg@1.2.3). Use --no-allow-scripts-pin to approve by package name for any future version.
How to add a new package that has install scripts
If you have --strict-allow-scripts enabled, there is a chicken-and-egg issue: the package needs to be installed before you can approve its scripts, but strict mode blocks the install. The default v12 behavior (no strict) handles this cleanly:
npm install -D esbuild # installs; postinstall skipped with warning
npm approve-scripts esbuild # writes the allowlist entry to package.json
npm rebuild esbuild # runs the now-approved postinstall
Commit the updated package.json and CI will pass because the allowlist entry is already there.
Git and remote dependencies require explicit approval
npm install will no longer resolve Git dependencies (direct or transitive) unless explicitly allowed via --allow-git. This closes a code-execution path where a Git dependency's .npmrc could override the Git executable, even with --ignore-scripts. This change has been available since npm 11.10.0 and was first announced in February 2026.
Similarly, dependencies from remote URLs (HTTPS tarballs, direct or transitive) will no longer resolve without --allow-remote. This flag has been available since npm 11.15.0.
If you have entries like "dep": "github:org/repo" or "dep": "https://example.com/pkg.tgz" anywhere in your tree, they stop resolving in v12:
# Allow a specific git dependency
npm install --allow-git=org/repo
# Persist for the project
npm config set allow-git=org/repo --location=project
# Same pattern for remote tarballs
npm install --allow-remote=https://example.com/pkg.tgz
npm config set allow-remote=https://example.com/pkg.tgz --location=project
Migration recipes by package type
Most projects only need to handle a handful of patterns. Find yours below.
Native modules (sharp, better-sqlite3, canvas, bcrypt, node-sass)
These are blocked even if they have no explicit install script, because npm runs an implicit node-gyp rebuild for any package with a binding.gyp. This includes many database drivers and image processing packages.
npm approve-scripts # approves node-gyp and each native package in your tree
Browser test runners (Cypress, Playwright, Puppeteer)
These use postinstall to download browser and runtime binaries.
npm approve-scripts # approves: cypress, playwright, @playwright/browser-*, puppeteer
Or skip the postinstall entirely and download binaries explicitly after install:
npx playwright install
npx cypress install
Electron
npm approve-scripts # approves: electron
Husky (git hooks)
npm approve-scripts # approves: husky
Alternatively, move Husky setup into an explicit prepare script that you invoke during project bootstrap rather than relying on the lifecycle hook.
Updating your CI pipeline
CI is where unprepared projects will break loudest. Before July:
- Upgrade your CI image to npm 11.16.0+
- Run
npm installin CI and check the logs for skipped-script warnings - Commit the allowlist from your local
npm approve-scripts --allrun — CI installs are reproducible once it is inpackage.json - Optionally add
--strict-allow-scriptsto your CI install command so the build fails loudly on anything unreviewed
Keep strict mode in CI rather than on developer machines, where the soft default (skip with warning) is more ergonomic when adding new packages.
Global installs and npx
npm approve-scripts and npm deny-scripts only work inside a project with a package.json. They error with EGLOBAL for global installs and npx. Use the --allow-scripts flag or config instead:
# One-off global install with scripts
npm install -g --allow-scripts=canvas,sharp <pkg>
# Persist to user config
npm config set allow-scripts=canvas,sharp --location=user
Migrating from ignore-scripts=true
If your .npmrc has ignore-scripts=true, the allowlist does not override it — ignore-scripts takes precedence and no scripts run regardless. The migration path:
# Build the allowlist while ignore-scripts is still set
npm approve-scripts --allow-scripts-pending # review what needs approval
npm approve-scripts --all # write the allowlist
# Then remove ignore-scripts=true from your .npmrc
Once ignore-scripts is removed, the allowlist takes over and only approved scripts run.
Checklist before July 2026
- Upgrade to npm 11.16.0+ and review install warnings
- Run
npm approve-scripts --allow-scripts-pendingto audit your tree - Run
npm approve-scripts --alland commit the updatedpackage.json - Update CI to npm 11.16.0+ and consider
--strict-allow-scripts - Check for any Git or remote URL dependencies and add
--allow-git/--allow-remoteconfig - If you maintain a package with install scripts, update your README to document
npm approve-scripts