Skip to main content

Staging Kindness: How NPM's New Release Gate Teaches Patience and Care

NPM's staged publishing feature adds a human approval step before packages go live. It's a lesson in kindness: slowing down, double-checking, and protecting the community from harm.

There's a quiet kindness in waiting. In the rush to ship software, we often forget that the people on the other end of the pipeline are just that—people. NPM's new staged publishing feature is a small but meaningful reminder: a gate before release, a moment to breathe, and a chance to catch mistakes before they ripple outward.

The feature, now officially live, adds an explicit maintainer approval step before a package version is available for installation. Instead of publishing directly to the world, the tarball goes to a staging queue, visible on npmjs.com and in the CLI. A human maintainer must then complete two-factor authentication to give the final go-ahead. The staging step itself doesn't require 2FA, so CI pipelines can still push artifacts non-interactively. The identity check happens at approval, not at submission.

To use it, you'll need npm CLI 11.15.0 or later and Node 22.14.0+. The package must already exist in the registry—no first-time publishes here. The workflow includes subcommands like npm stage publish, npm stage list, npm stage view <stage-id>, npm stage approve <stage-id>, and npm stage reject <stage-id>. Straightforward enough.

Why Bother with a Staging Step?

Because kindness is also about safeguarding. The software supply chain has been under fire. The Shai-Hulud worm attack and the deprecation of traditional tokens are fresh wounds. Security researcher Adnan Khan put it bluntly on X: every developer publishing to NPM should enable this feature right away. Use OIDC in CI, stage the release, review before it goes public. Shai-Hulud? Rejected.

The staging step doesn't just protect end users; it protects maintainers from themselves. We've all hit publish too soon, only to scramble with a hotfix. Staging gives you a deliberate pause. You can inspect the tarball, run a quick test, and then approve. It's a small act of self-care that pays off in trust.

What the Community Says

Reactions have been mixed, which is healthy. Hacker News user weinzierl called it a band-aid, worrying that it might undermine long-term infrastructure security efforts. Another user countered: how could it be harmful? For trusted publishing, this isn't a band-aid—it's a major improvement, closing off a whole class of attacks that hijack CI to push malicious packages. Attackers will find other ways, sure, but this plugs a huge hole.

Some doubt adoption. User turkeyboi noted that it only helps if maintainers actually use it. Klaster_1 wondered whether it should be mandatory by default. A Reddit commenter argued that it only slows the spread of malicious packages, not a cure for supply-chain ills. These are fair points. But any step that introduces a human checkpoint is a step toward care.

Kindness in Practice: The Staging Workflow

Think of staging as a front porch. You don't throw the door open to strangers without a peek through the window. The staged package sits there, waiting, while you decide. And the CLI gives you all the tools to make an informed choice.

  • npm stage publish – Submit the version to the stage queue.
  • npm stage list – See what's awaiting approval.
  • npm stage view <stage-id> – Inspect the tarball contents.
  • npm stage approve <stage-id> – Promote it to the registry, prompting for 2FA.
  • npm stage reject <stage-id> – Discard it.

GitHub suggests combining staging with OIDC-based trusted publishing, restricting config to allow only staged releases. That way, any direct npm publish from CI gets rejected. If you're already using trusted publishing, you can reuse that config to migrate packages. Just update your CI environment to the new CLI and swap the publish command.

Beyond the Gate: New Flags and Future Plans

This release also adds --allow-file, --allow-remote, and --allow-directory flags, alongside the existing --allow-git. These can be set to all or none in .npmrc or package.json. In v12, --allow-git defaults to none. The CLI docs list flags like --tag and --provenance, which behave just like npm publish.

GitHub's roadmap includes making fine-grained access tokens default to staging-only, bypassing 2FA, and adding an allowScripts field in v12 to keep install scripts off by default. These are thoughtful changes, each one a little more kindness baked into the system.

The Ripple Effect

Competitors are quick to follow. pnpm 11.3 added pnpm stage with the same subcommands. Yarn offers something similar, and release-it supports a "stage": true option. pnpm also delays installing freshly published versions by default as a protective measure. The industry is moving toward slower, more careful releases.

This isn't just about security. It's about respect for the people who use your work. Every time you publish a package, you're making a promise that it won't break their build, steal their data, or compromise their system. Staging is a way to honor that promise.

A Personal Note

I remember the first time I published an npm package. I was nervous, excited, and a little reckless. I hit publish without checking the tarball. It worked, but I've since learned the value of a pause. Staging is like taking a deep breath before sending an email you might regret. It's a small act of kindness toward your future self and your users.

Is it a cure-all? No. But it's a start. And in a world that moves too fast, a deliberate pause is a radical act. So go ahead, enable staging. Be kind to your releases, and they'll be kind to you.

Share this article:

Comments (0)

No comments yet. Be the first to comment!