Publishing an npm package is usually a simple process. A developer updates the package version, runs the build, and publishes it to the npm registry.
The problem is that a package release can affect thousands of applications within minutes.
A mistake in the package, a compromised publishing environment, or an incorrect release can quickly reach users. This is why npm has been adding stronger controls around package publishing.
Staged publishing provides a safer way to release npm packages by separating the process of preparing a package from making that package generally available. Instead of immediately pushing every new version to all consumers, package maintainers can use a controlled publishing flow.
This article explains what staged publishing means, how it changes the npm release process, why it is useful for CI/CD pipelines, and what developers should consider before adopting it.
What Is npm Staged Publishing?
Staged publishing is a release approach where a package is prepared and published through an intermediate stage before it becomes broadly available.
A traditional npm workflow often looks like this:
Developer
|
v
Build package
|
v
npm publish
|
v
Package available to consumersThe release becomes available as soon as the publishing operation succeeds.
With a staged approach, the workflow becomes more controlled:
Developer
|
v
Build package
|
v
Publish to staging
|
v
Validate package
|
v
Promote release
|
v
Consumers receive releaseThe important difference is the promotion step.
A package can be prepared and checked before maintainers make it available as the normal release.
This can reduce the impact of mistakes during package publishing.
Why Package Publishing Needs More Controls
npm packages are often used as building blocks for larger applications.
For example, an application might depend on:
{
"dependencies": {
"example-library": "^4.2.0"
}
}When a package is released, downstream applications may eventually consume the new version.
A package release can therefore affect:
Application builds
CI/CD pipelines
Developer environments
Production deployments
Other npm packages
Automated dependency updates
A small packaging mistake can become a much larger problem once the package is distributed.
Consider a package where the published build accidentally contains development files:
package/
├── dist/
├── src/
├── tests/
├── .env
└── internal-config.jsonIf the package is immediately released, consumers may download files that were never intended to leave the development environment.
A staged release provides another point at which maintainers can inspect the package.
Traditional npm Publishing vs Staged Publishing
The difference is easiest to understand by comparing the workflows.
Area | Traditional Publishing | Staged Publishing |
|---|---|---|
Package preparation | Build and publish | Build and stage |
Availability | Direct | Controlled promotion |
Validation window | Limited | Available before promotion |
Release control | Lower | Higher |
CI/CD integration | Simple | More controlled |
Risk of immediate bad release | Higher | Lower |
Release process | Faster | Adds an additional step |
Traditional publishing is still useful for simple projects.
Staged publishing becomes more valuable as the package becomes more important to other applications.
A Typical Staged Release Workflow
A practical release pipeline might look like this:
Step 1: Update the Package
The developer changes the package code.
export function formatUserName(user) {
return `${user.firstName} ${user.lastName}`;
}Tests are then added or updated.
import { formatUserName } from "./user.js";
const user = {
firstName: "John",
lastName: "Smith"
};
console.log(formatUserName(user));Step 2: Build the Package
The CI pipeline creates the distribution files.
For example:
npm ci
npm test
npm run buildThe build should produce only the files intended for consumers.
Step 3: Prepare the Release
The package version is updated according to the project's release policy.
For example:
{
"name": "example-library",
"version": "2.4.0"
}Step 4: Stage the Package
Instead of immediately treating the package as the final release, the publishing workflow places it into the controlled release stage.
This gives maintainers an opportunity to verify the package.
Step 5: Validate the Release
The team can check:
Package contents
Version number
Dependencies
Generated files
Type declarations
Documentation
License files
Tests
Security scanning
Installation behavior
Step 6: Promote the Release
After validation, the release can be made available to normal consumers.
This creates a deliberate boundary between publishing a package artifact and releasing it broadly.
Why This Matters for CI/CD
Modern npm packages are often published automatically.
A simplified GitHub Actions workflow might look like this:
name: Publish Package
on:
push:
tags:
- "v*"
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build package
run: npm run buildAutomated publishing is convenient, but it also means a mistake in the pipeline can become a released package without a person reviewing the final artifact.
Staged publishing fits well into this type of workflow because it allows the pipeline to separate:
Build
↓
Test
↓
Package
↓
Stage
↓
Validate
↓
PromoteThat is generally easier to control than:
Build
↓
Test
↓
PublishInspect the Package Before Releasing It
One of the most useful checks in any npm publishing workflow is inspecting exactly what will be included.
You can use:
npm pack --dry-runThis helps you understand what npm will include in the package.
A package can contain more than developers expect.
For example:
dist/
README.md
LICENSE
package.json
src/
tests/If the package is intended to expose only compiled code, including src/ and tests/ may be unnecessary.
The files property in package.json can help control what gets published:
{
"name": "example-library",
"version": "2.4.0",
"files": [
"dist"
]
}This is a useful production practice regardless of whether a staged release process is used.
Staged Publishing and Security
Package publishing is not only a release-management problem. It is also a security problem.
A compromised publishing credential could allow an attacker to release malicious code.
A safer pipeline should therefore combine staged publishing with strong authentication controls.
For example:
Source Repository
|
v
CI/CD Pipeline
|
+--> Tests
|
+--> Security Checks
|
+--> Package Validation
|
v
Staged Release
|
v
Promotion
|
v
npm ConsumersThe staged process does not replace secure credentials.
It should be combined with:
Short-lived authentication where supported
Protected CI/CD environments
Restricted publishing permissions
Review requirements
Dependency security checks
Audit logging
Staged Publishing Does Not Replace Testing
It is easy to misunderstand the purpose of a staged release.
Staging does not mean:
"We can publish broken packages and fix them later."
The goal is to provide an additional control point.
You should still run automated tests before staging.
For example:
npm ci
npm run lint
npm test
npm run build
npm pack --dry-runYou can also install the generated package into a clean test project.
For example:
mkdir package-test
cd package-test
npm init -y
npm install ../example-library/example-library-2.4.0.tgzThen test the package as an actual consumer would.
This can catch problems that unit tests inside the original repository may not detect.
Testing the Published Package as a Consumer
One common mistake is testing source code rather than the final npm artifact.
Suppose the repository contains:
src/
tests/
dist/
package.jsonYour local tests might import from src/.
But consumers may import:
import { calculateTotal } from "example-library";The package's main, module, exports, or type configuration may therefore introduce problems that source-level tests never see.
A better release check is:
Build the package.
Generate the package artifact.
Install that artifact into a clean project.
Import the public API.
Run consumer-level tests.
For example:
import { calculateTotal } from "example-library";
const result = calculateTotal([10, 20, 30]);
if (result !== 60) {
throw new Error("Package validation failed");
}This gives the team more confidence in what consumers will actually receive.
Common Mistakes
Publishing Directly From a Developer Laptop
Manual publishing from local machines makes the release process dependent on individual developer environments.
Different Node.js versions, npm versions, credentials, and local files can produce unexpected results.
For important packages, publishing through a controlled CI/CD process is usually easier to audit.
Skipping Package Inspection
A repository can be clean while the published package is not.
Always inspect the package artifact.
Assuming Tests Guarantee a Safe Release
Tests can verify application behavior, but they do not necessarily verify package contents, publishing metadata, or release configuration.
Giving Every Developer Publishing Permission
Publishing permissions should be limited.
Developers who do not need release permissions should not automatically have them.
Treating Staging as a Replacement for Reviews
A staged workflow creates a safety checkpoint. It does not eliminate the need for appropriate review and automated validation.
Best Practices for npm Staged Releases
Keep Build and Release Separate
A clean pipeline should distinguish between creating the package and releasing it.
Build → Test → Package → Stage → Validate → PromoteThis makes failures easier to identify.
Use Automated Validation
Do not depend only on manual inspection.
Automate checks for:
Tests
Linting
Type checking
Package contents
Dependency issues
Version consistency
Installation behavior
Protect the Promotion Step
The final promotion should have stronger controls than ordinary builds.
Depending on the team's release policy, this can include environment protection, approval, or restricted permissions.
Keep Release Credentials Out of Source Code
Never put npm credentials directly into source files.
Bad:
const npmToken = "actual-token";Better:
const npmToken = process.env.NPM_TOKEN;The token should be managed by the CI/CD environment.
Use Reproducible Builds
A package should be generated from a known source revision using a predictable build environment.
This makes it easier to determine exactly what was released.
Advantages of Staged Publishing
Reduced Release Risk
A package can be validated before broad availability.
Better CI/CD Control
The release process can have explicit stages rather than a single publishing operation.
Easier Auditing
The team can identify when a package was built, staged, validated, and promoted.
Safer High-Impact Releases
The approach is especially useful for libraries that have many downstream consumers.
Better Separation of Responsibilities
Development, package creation, validation, and release can be treated as separate operations.
Disadvantages
Additional Release Complexity
A staged workflow introduces another step that teams must understand and maintain.
Slightly Slower Releases
A package may take longer to reach consumers because it passes through an additional validation stage.
More CI/CD Configuration
Teams need to configure and maintain the appropriate pipeline permissions and release controls.
Not Necessary for Every Package
A small internal package with very limited usage may not need the same release process as a widely consumed public library.
When Should You Use Staged Publishing?
Staged publishing is particularly useful when:
Your package has many consumers.
Releases are generated automatically.
The package is business-critical.
A bad release could break production applications.
Multiple developers can publish packages.
You need stronger release governance.
Your organization has security or compliance requirements.
For a small experimental package, a simpler workflow may be sufficient.
The important point is to match the release process with the impact of a failed release.
A Practical npm Release Checklist
Before promoting a package, verify:
The version number is correct.
Tests pass.
The production build succeeds.
The package contents have been inspected.
No credentials or private files are included.
Dependencies are correct.
Type declarations are included when required.
The public API works from a clean project.
CI/CD authentication is configured securely.
Publishing permissions are restricted.
The release artifact matches the intended source revision.
The promotion step has appropriate protection.
Summary
npm package publishing is easy to automate, but automation also increases the importance of having strong release controls.
Staged publishing introduces a useful separation between preparing a package and making that package broadly available. Instead of treating npm publish as the final and immediate step, teams can build, test, inspect, stage, validate, and then promote a release.
For production npm packages, this approach can reduce the chance that a bad artifact reaches consumers and gives teams a clearer release process.
The strongest setup is not staged publishing alone. Combine it with automated testing, package inspection, secure authentication, restricted publishing permissions, reproducible builds, and consumer-level validation.
That turns npm publishing from a single command into a controlled release process that is much easier to operate safely at scale.

Join the conversation! Your thoughts help the community grow.