Add documentation for staged publishing (#1961)
## Summary Updates npm publishing documentation for staged publishing and trusted publishing. - clarifies direct publishing vs. staged publishing requirements in package publishing docs - simplifies the staged publishing guide to focus on the user workflow - adds npmjs.com screenshots for reviewing and approving staged packages - updates trusted publisher screenshots and related documentation copy
Karen Li committed
May 20, 2026 at 11:10 UTC
203cdd5dffbd5dc5a125f3b750717f69fd652171
11 files changed
+278
-22
content/nav.yml
+2
@@ -158,6 +158,8 @@
158
url: /generating-provenance-statements
159
- title: Trusted publishing with OIDC
160
url: /trusted-publishers
161
+ - title: Staged publishing
162
+ url: /staged-publishing
163
- title: About ECDSA registry signatures
164
url: /about-registry-signatures
165
- title: Verifying ECDSA registry signatures
content/packages-and-modules/contributing-packages-to-the-registry/creating-and-publishing-private-packages.mdx
+46
-6
@@ -81,16 +81,19 @@ npm install my-package
81
82
By default, scoped packages are published with private visibility.
83
84
-<Note variant="warning">
84
+There are two ways to publish your package to the npm registry:
85
86
-**Important:** Publishing to npm requires either:
86
+1. [Direct publishing](#direct-publishing)
87
+2. [Staged publishing](#staged-publishing)
88
88
-- Two-factor authentication (2FA) enabled on your account, OR
89
-- A granular access token with bypass 2FA enabled
89
+### Direct publishing
90
91
-For more information, see the npm documentation on [requiring 2FA for package publishing](/requiring-2fa-for-package-publishing-and-settings-modification).
91
+To publish directly with `npm publish`, you need either:
92
93
-</Note>
93
+- Two-factor authentication (2FA) enabled on your account, or
94
+- A granular access token (GAT) with bypass 2FA enabled
95
+
96
+For more information, see the npm documentation on [requiring 2FA for package publishing](/requiring-2fa-for-package-publishing-and-settings-modification).
97
98
1. On the command line, navigate to the root directory of your package.
99
@@ -110,6 +113,42 @@ For more information, see the npm documentation on [requiring 2FA for package pu
113
114
For more information on the `publish` command, see the [CLI documentation][cli-publish].
115
116
+### Staged publishing
117
+
118
+Instead of publishing directly, you can stage your package and approve it later. Staging the package does not require 2FA, which allows CI workflows to submit a package to the staging area. Before the package is published to the registry, a maintainer must review and approve it with 2FA.
119
+
120
+A GAT with bypass 2FA does not bypass the 2FA check during staged package approval.
121
+
122
+1. On the command line, navigate to the root directory of your package.
123
+
124
+ ```
125
+ cd /path/to/package
126
+ ```
127
+
128
+2. To stage your package, run:
129
+
130
+ ```
131
+ npm stage publish
132
+ ```
133
+
134
+ This submits your package to a staging area.
135
+
136
+3. To check that your package has been staged, use either of the following methods:
137
+ - In the CLI, run `npm stage list <package-name>` to find the staged package and its stage ID.
138
+ - On [npmjs.com](https://www.npmjs.com), open the **Staged Packages** tab to review staged packages.
139
+
140
+4. To approve and publish the staged package, use one of the following methods:
141
+ - In the CLI, run the `npm stage approve <stage-id>` command.
142
+ - On [npmjs.com](https://www.npmjs.com), review the staged package in the **Staged Packages** tab, then click **Approve**.
143
+
144
+ <Note>
145
+
146
+ **Note:** You will be prompted for 2FA verification regardless of whether you approve the package in the CLI or on [npmjs.com](https://www.npmjs.com). Once approved, the package is published to the live registry.
147
+
148
+ </Note>
149
+
150
+For the full staged publishing workflow, including reviewing, inspecting, and rejecting staged packages, see [Staged publishing][staged-publishing].
151
+
152
[scopes]: about-scopes
153
[private-pkgs]: about-private-packages
154
[user-signup]: https://www.npmjs.com/signup
@@ -123,3 +162,4 @@ For more information on the `publish` command, see the [CLI documentation][cli-p
162
[config-2fa]: /configuring-two-factor-authentication
163
[creating-token]: /creating-and-viewing-access-tokens
164
[requiring-2fa]: /requiring-2fa-for-package-publishing-and-settings-modification
165
+[staged-publishing]: /staged-publishing
content/packages-and-modules/contributing-packages-to-the-registry/creating-and-publishing-scoped-public-packages.mdx
+46
-6
@@ -77,16 +77,19 @@ npm install /path/to/my-test-package
77
78
By default, scoped packages are published with private visibility. To publish a scoped package with public visibility, use `npm publish --access public`.
79
80
-<Note variant="warning">
80
+There are two ways to publish your package to the npm registry:
81
82
-**Important:** Publishing to npm requires either:
82
+1. [Direct publishing](#direct-publishing)
83
+2. [Staged publishing](#staged-publishing)
84
84
-- Two-factor authentication (2FA) enabled on your account, OR
85
-- A granular access token with bypass 2FA enabled
85
+### Direct publishing
86
87
-For more information, see the npm documentation on [requiring 2FA for package publishing](/requiring-2fa-for-package-publishing-and-settings-modification).
87
+To publish directly with `npm publish --access public`, you need either:
88
89
-</Note>
89
+- Two-factor authentication (2FA) enabled on your account, or
90
+- A granular access token (GAT) with bypass 2FA enabled
91
+
92
+For more information, see the npm documentation on [requiring 2FA for package publishing](/requiring-2fa-for-package-publishing-and-settings-modification).
93
94
1. On the command line, navigate to the root directory of your package.
95
@@ -112,6 +115,42 @@ For more information, see the npm documentation on [requiring 2FA for package pu
115
116
For more information on the `publish` command, see the [CLI documentation][cli-publish].
117
118
+### Staged publishing
119
+
120
+Instead of publishing directly, you can stage your package and approve it later. Staging the package does not require 2FA, which allows CI workflows to submit a package to the staging area. Before the package becomes publicly available, a maintainer must review and approve it with 2FA.
121
+
122
+A GAT with bypass 2FA does not bypass the 2FA check during staged package approval.
123
+
124
+1. On the command line, navigate to the root directory of your package.
125
+
126
+ ```
127
+ cd /path/to/my-test-package
128
+ ```
129
+
130
+2. To stage your scoped public package, run:
131
+
132
+ ```
133
+ npm stage publish
134
+ ```
135
+
136
+ This submits your package to a staging area.
137
+
138
+3. To check that your package has been staged, use either of the following methods:
139
+ - In the CLI, run `npm stage list <package-name>` to find the staged package and its stage ID.
140
+ - On [npmjs.com](https://www.npmjs.com), open the **Staged Packages** tab to review staged packages.
141
+
142
+4. To approve and publish the staged package, use one of the following methods:
143
+ - In the CLI, run the `npm stage approve <stage-id>` command.
144
+ - On [npmjs.com](https://www.npmjs.com), review the staged package in the **Staged Packages** tab, then click **Approve**.
145
+
146
+ <Note>
147
+
148
+ **Note:** You will be prompted for 2FA verification regardless of whether you approve the package in the CLI or on [npmjs.com](https://www.npmjs.com). Once approved, the package is published to the live registry.
149
+
150
+ </Note>
151
+
152
+For the full staged publishing workflow, including reviewing, inspecting, and rejecting staged packages, see [Staged publishing][staged-publishing].
153
+
154
[scopes]: /about-scopes
155
[user-signup]: https://www.npmjs.com/signup
156
[create-org]: https://www.npmjs.com/signup?next=/org/create
@@ -125,3 +164,4 @@ For more information on the `publish` command, see the [CLI documentation][cli-p
164
[config-2fa]: /configuring-two-factor-authentication
165
[creating-token]: /creating-and-viewing-access-tokens
166
[requiring-2fa]: /requiring-2fa-for-package-publishing-and-settings-modification
167
+[staged-publishing]: /staged-publishing
content/packages-and-modules/contributing-packages-to-the-registry/creating-and-publishing-unscoped-public-packages.mdx
+46
-6
@@ -58,16 +58,19 @@ npm install path/to/my-package
58
59
## Publishing unscoped public packages
60
61
-<Note variant="warning">
61
+There are two ways to publish your package to the npm registry:
62
63
-**Important:** Publishing to npm requires either:
63
+1. [Direct publishing](#direct-publishing)
64
+2. [Staged publishing](#staged-publishing)
65
65
-- Two-factor authentication (2FA) enabled on your account, OR
66
-- A granular access token with bypass 2FA enabled
66
+### Direct publishing
67
68
-For more information, see the npm documentation on [requiring 2FA for package publishing](/requiring-2fa-for-package-publishing-and-settings-modification).
68
+To publish directly with `npm publish`, you need either:
69
70
-</Note>
70
+- Two-factor authentication (2FA) enabled on your account, or
71
+- A granular access token (GAT) with bypass 2FA enabled
72
+
73
+For more information, see the npm documentation on [requiring 2FA for package publishing](/requiring-2fa-for-package-publishing-and-settings-modification).
74
75
1. On the command line, navigate to the root directory of your package.
76
@@ -91,6 +94,42 @@ For more information, see the npm documentation on [requiring 2FA for package pu
94
95
For more information on the `publish` command, see the [CLI documentation][cli-publish].
96
97
+### Staged publishing
98
+
99
+Instead of publishing directly, you can stage your package and approve it later. Staging the package does not require 2FA, which allows CI workflows to submit a package to the staging area. Before the package becomes publicly available, a maintainer must review and approve it with 2FA.
100
+
101
+A GAT with bypass 2FA does not bypass the 2FA check during staged package approval.
102
+
103
+1. On the command line, navigate to the root directory of your package.
104
+
105
+ ```
106
+ cd /path/to/package
107
+ ```
108
+
109
+2. To stage your package, run:
110
+
111
+ ```
112
+ npm stage publish
113
+ ```
114
+
115
+ This submits your package to a staging area.
116
+
117
+3. To check that your package has been staged, use either of the following methods:
118
+ - In the CLI, run `npm stage list <package-name>` to find the staged package and its stage ID.
119
+ - On [npmjs.com](https://www.npmjs.com), open the **Staged Packages** tab to review staged packages.
120
+
121
+4. To approve and publish the staged package, use one of the following methods:
122
+ - In the CLI, run the `npm stage approve <stage-id>` command.
123
+ - On [npmjs.com](https://www.npmjs.com), review the staged package in the **Staged Packages** tab, then click **Approve**.
124
+
125
+ <Note>
126
+
127
+ **Note:** You will be prompted for 2FA verification regardless of whether you approve the package in the CLI or on [npmjs.com](https://www.npmjs.com). Once approved, the package is published to the live registry.
128
+
129
+ </Note>
130
+
131
+For the full staged publishing workflow, including reviewing, inspecting, and rejecting staged packages, see [Staged publishing][staged-publishing].
132
+
133
[pkg-viz]: package-scope-access-level-and-visibility
134
[user-signup]: https://www.npmjs.com/signup
135
[create-org]: https://www.npmjs.com/signup?next=/org/create
@@ -103,3 +142,4 @@ For more information on the `publish` command, see the [CLI documentation][cli-p
142
[config-2fa]: /configuring-two-factor-authentication
143
[creating-token]: /creating-and-viewing-access-tokens
144
[requiring-2fa]: /requiring-2fa-for-package-publishing-and-settings-modification
145
+[staged-publishing]: /staged-publishing
content/packages-and-modules/securing-your-code/staged-publishing.mdx
new
+122
@@ -0,0 +1,122 @@
1
+---
2
+title: Staged publishing for npm packages
3
+---
4
+
5
+Staged publishing adds an approval step before packages go live on the npm registry. Instead of publishing directly with `npm publish`, you can submit packages to a staging area with `npm stage publish`. A maintainer must then review and explicitly approve the staged package — with two-factor authentication (2FA) via the CLI or [npmjs.com](https://www.npmjs.com) — before it becomes publicly available.
6
+
7
+Staged publishing is useful when you want an extra review step before a package version becomes available on the registry.
8
+
9
+<Note>
10
+
11
+**Note:** Staged publishing requires [npm CLI](https://docs.npmjs.com/cli/v11) version 11.15.0 or later and Node version 22.14.0 or higher.
12
+
13
+</Note>
14
+
15
+## How staged publishing works
16
+
17
+Staged publishing has three steps:
18
+
19
+1. [Stage a package](#stage-a-package)
20
+2. [Review a staged package](#review-a-staged-package)
21
+3. [Approve a staged package](#approve-a-staged-package)
22
+
23
+## Prerequisites
24
+
25
+Before using staged publishing, ensure the following:
26
+
27
+- You have **publish access** to the package
28
+- The package **already exists** on the npm registry — you cannot stage a brand-new package
29
+- **2FA is enabled** on your npm account
30
+
31
+## Stage a package
32
+
33
+1. On the command line, navigate to the root directory of your package.
34
+
35
+ ```
36
+ cd /path/to/package
37
+ ```
38
+
39
+2. To stage your package, run:
40
+
41
+ ```
42
+ npm stage publish
43
+ ```
44
+
45
+ This submits your package to a staging area.
46
+
47
+<Note>
48
+
49
+**Note:** `npm stage publish` does not require 2FA.
50
+
51
+</Note>
52
+
53
+## Review a staged package
54
+
55
+After you stage a package, you can inspect it in the CLI or on [npmjs.com](https://www.npmjs.com).
56
+
57
+#### Using the CLI
58
+
59
+To list staged packages you have access to:
60
+
61
+```
62
+npm stage list [<package-spec>]
63
+```
64
+
65
+To view details for a specific staged package:
66
+
67
+```
68
+npm stage view <stage-id>
69
+```
70
+
71
+To download the staged package tarball for inspection:
72
+
73
+```
74
+npm stage download <stage-id>
75
+```
76
+
77
+#### Using npmjs.com
78
+
79
+Open the **Staged Packages** tab to review staged packages and find the package you want to approve.
80
+
81
+<Screenshot
82
+ src="/packages-and-modules/securing-your-code/staged-package-tab.png"
83
+ alt="Screenshot showing the Staged Packages tab on npmjs.com with staged packages ready for review"
84
+/>
85
+
86
+## Approve a staged package
87
+
88
+To publish a staged package to the registry, approve it with 2FA.
89
+
90
+#### Using the CLI
91
+
92
+To approve a staged package and publish it to the live registry:
93
+
94
+```
95
+npm stage approve <stage-id>
96
+```
97
+
98
+#### Using npmjs.com
99
+
100
+On [npmjs.com](https://www.npmjs.com), review the staged package in the **Staged Packages** tab, then click **Approve**.
101
+
102
+<Screenshot
103
+ src="/packages-and-modules/securing-your-code/staged-package-approve.png"
104
+ alt="Screenshot showing a staged package on npmjs.com with the Approve button"
105
+/>
106
+
107
+<Note>
108
+
109
+**Note:** You will be prompted for 2FA verification whether you approve the package in the CLI or on [npmjs.com](https://www.npmjs.com).
110
+
111
+</Note>
112
+
113
+## Using staged publishing with trusted publishers
114
+
115
+If you use [trusted publishing (OIDC)](/trusted-publishers) from CI/CD, you can use staged publishing to submit a package for review before it goes live. A maintainer must still review and approve the staged package with 2FA.
116
+
117
+For more information on configuring trusted publisher permissions, see "[Trusted publishing for npm packages](/trusted-publishers#configuring-allowed-actions)."
118
+
119
+## Learn more
120
+
121
+- [Trusted publishing for npm packages](./trusted-publishers)
122
+- [Generating provenance statements](./generating-provenance-statements)
content/packages-and-modules/securing-your-code/trusted-publishers.mdx
+16
-4
@@ -45,6 +45,7 @@ Configure the following fields:
45
- Must include the `.yml` or `.yaml` extension
46
- The workflow file must exist in `.github/workflows/` in your repository
47
- **Environment name** (optional): If using [GitHub environments](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment) for deployment protection
48
+- **Allowed actions** (required): Select which actions this trusted publisher can perform — `npm publish`, `npm stage publish`, or both. At least one must be selected. See [Staged publishing for npm packages](/staged-publishing) for more information on staged publishing.
49
50
<Screenshot src="/packages-and-modules/securing-your-code/trusted-publisher-github-actions.png" alt="Screenshot of GitHub Actions trusted publisher configuration form" />
51
@@ -57,6 +58,7 @@ Configure the following fields:
58
- **Top-level CI file path** (required): The path to your CI file (e.g., `.gitlab-ci.yml`)
59
- Must include the `.yml` extension
60
- **Environment name** (optional): If using [GitLab environments](https://docs.gitlab.com/ee/ci/environments/)
61
+- **Allowed actions** (required): Select which actions this trusted publisher can perform — `npm publish`, `npm stage publish`, or both. At least one must be selected.
62
63
<Screenshot src="/packages-and-modules/securing-your-code/trusted-publisher-gitlab.png" alt="Screenshot of GitLab CI/CD trusted publisher configuration form" />
64
@@ -69,6 +71,7 @@ Configure the following fields:
71
- **Pipeline definition ID** (required): The pipeline definition ID (UUID format). You may find it from your CircleCI Project Settings under Project Setup page.
72
- **VCS origin** (required): The VCS origin URL for your project (e.g., `github.com/myorg/myrepo`)
73
- **Context IDs** (optional): Restrict publishing to jobs using specific CircleCI contexts. You may find them from your CircleCI Organization Settings Contexts.
74
+- **Allowed actions** (required): Select which actions this trusted publisher can perform — `npm publish`, `npm stage publish`, or both. At least one must be selected.
75
76
<Screenshot src="/packages-and-modules/securing-your-code/trusted-publisher-circleci.png" alt="Screenshot of CircleCI trusted publisher configuration form" />
77
@@ -78,6 +81,12 @@ Configure the following fields:
81
82
</Note>
83
84
+<Note>
85
+
86
+**Note:** Trusted publisher configurations created before May 20, 2026 are automatically set to allow `npm publish` only — no behavior change occurs for current workflows. Configurations created after May 20, 2026 require you to explicitly select at least one allowed action.
87
+
88
+</Note>
89
+
90
### Step 2: Configure your CI/CD workflow
91
92
#### GitHub Actions configuration
@@ -110,7 +119,7 @@ jobs:
119
- run: npm ci
120
- run: npm run build --if-present
121
- run: npm test
113
- - run: npm publish
122
+ - run: npm publish # Or: npm stage publish
123
```
124
125
The critical requirement is the `id-token: write` permission, which allows GitHub Actions to generate OIDC tokens. Learn more in [GitHub's OIDC documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect).
@@ -146,7 +155,7 @@ publish:
155
script:
156
- npm ci
157
- npm run build --if-present
149
- - npm publish
158
+ - npm publish # Or: npm stage publish
159
only:
160
- tags
161
```
@@ -185,7 +194,7 @@ jobs:
194
name: Publish to npm with OIDC
195
command: |
196
export NPM_ID_TOKEN=$(circleci run oidc get --claims '{"aud": "npm:registry.npmjs.org"}')
188
- npm publish
197
+ npm publish # Or: npm stage publish
198
199
workflows:
200
publish:
@@ -218,6 +227,8 @@ Once you've configured trusted publishers for your package, we strongly recommen
227
228
Trusted publishers use short-lived, scoped credentials that are generated on-demand during your CI/CD workflow, eliminating the need for long-lived tokens. By restricting traditional token access while using trusted publishers, you reduce potential security risks associated with credential management.
229
230
+For even stronger security, configure your trusted publisher with **stage-only permissions** (allow `npm stage publish` but not `npm publish`). This ensures all CI-automated publishes go through the [staged publishing](/staged-publishing) flow, requiring a maintainer to review and approve each package with 2FA via the CLI or [npmjs.com](https://www.npmjs.com) before it becomes publicly available. Combined with disallowing tokens, this provides the maximum security posture for your packages.
231
+
232
**Note:** The "disallow tokens" setting only affects traditional token authentication. Your trusted publishers will continue to work normally, as they use OIDC tokens.
233
234
### Migration tip
@@ -346,12 +357,13 @@ Some GitHub Actions workflows use `workflow_call` to invoke other workflows that
357
358
Trusted publishing currently supports only cloud-hosted runners. Support for self-hosted runners is intended for a future release. Each package can only have one trusted publisher configured at a time, though you can update this configuration as needed.
359
349
-OIDC authentication is currently limited to the publish operation. Other npm commands such as `install`, `view`, or `access` still require traditional authentication methods. The `npm whoami` command will not reflect OIDC authentication status since the authentication occurs only during the publish operation.
360
+OIDC authentication supports the `npm publish` and `npm stage publish` commands. Other stage subcommands (`npm stage list`, `npm stage view`, `npm stage approve`, `npm stage reject`) require interactive authentication and cannot use OIDC tokens, as these actions require proof of presence and can only be performed via the CLI or [npmjs.com](https://www.npmjs.com). Other npm commands such as `install`, `view`, or `access` still require traditional authentication methods. The `npm whoami` command will not reflect OIDC authentication status since the authentication occurs only during the publish or stage operation.
361
362
We intend to expand trusted publishing support to additional CI/CD providers and enhance the feature based on community feedback.
363
364
## Learn more
365
366
+- [Staged publishing for npm packages](./staged-publishing)
367
- [About npm provenance](./generating-provenance-statements)
368
- [OpenSSF Trusted Publishers specification](https://repos.openssf.org/trusted-publishers-for-all-package-repositories)
369
- [GitHub Actions OIDC documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
static/packages-and-modules/securing-your-code/staged-package-approve.png
Binary files /dev/null and b/static/packages-and-modules/securing-your-code/staged-package-approve.png differ
static/packages-and-modules/securing-your-code/staged-package-tab.png
Binary files /dev/null and b/static/packages-and-modules/securing-your-code/staged-package-tab.png differ
static/packages-and-modules/securing-your-code/trusted-publisher-circleci.png
Binary files a/static/packages-and-modules/securing-your-code/trusted-publisher-circleci.png and b/static/packages-and-modules/securing-your-code/trusted-publisher-circleci.png differ
static/packages-and-modules/securing-your-code/trusted-publisher-github-actions.png
Binary files a/static/packages-and-modules/securing-your-code/trusted-publisher-github-actions.png and b/static/packages-and-modules/securing-your-code/trusted-publisher-github-actions.png differ
static/packages-and-modules/securing-your-code/trusted-publisher-gitlab.png
Binary files a/static/packages-and-modules/securing-your-code/trusted-publisher-gitlab.png and b/static/packages-and-modules/securing-your-code/trusted-publisher-gitlab.png differ