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