@@ -39,24 +39,47 @@ official release builds for Node.js, hosted on <https://nodejs.org/>.
3939
4040## Who can make a release?
4141
42- Release authorization is given by the Node.js TSC. Once authorized, an
43- individual must have the following:
42+ There is a distinction between individuals who can "prepare" a release by
43+ adding the commits to the branches in GitHub and those who can "publish" the
44+ releases to nodejs.org.
45+
46+ Individuals who are Members of the
47+ [ backporters team] ( https://github.com/orgs/nodejs/teams/backporters )
48+ (restricted link) can land things on the staging branches and prepare
49+ releases including creating the proposal branches which will be discussed
50+ later in this document.
51+
52+ Authorization to publish releases is given by the Node.js TSC. This is
53+ required to publish a release after it has been prepared. If you are working
54+ on preparing a release for the first time you will be able to do most of the
55+ steps as a member of the backporters team and have someone else who is
56+ already onboarded promote the release on your behalf. Once authorized by the
57+ TSC as a releaser, an individual will require the following to publish
58+ releases themselves:
4459
4560### 1. Jenkins release access
4661
47- There are three relevant Jenkins jobs that should be used for a release flow:
62+ There are four relevant Jenkins jobs that should be used for a release flow:
4863
4964** a.** ** Test runs:**
5065** [ node-test-pull-request] ( https://ci.nodejs.org/job/node-test-pull-request/ ) **
5166is used for a final full-test run to ensure that the current _ HEAD_ is stable.
5267
53- ** b.** ** Nightly builds:** (optional)
68+ ** b.** ** CitGM:**
69+ ** [ citgm-smoker] ( https://ci.nodejs.org/job/citgm-smoker/ ) ** is used to run
70+ the [ CitGM] ( https://github.com/nodejs/citgm/ ) tool which tests a build of
71+ Node.js against a defined set of community modules. This is used during a
72+ release process to ensure that none of the commonly used modules which are
73+ tested by CitGM show functional regressions with the new Node.js version
74+ which could impact users.
75+
76+ ** c.** ** Nightly builds:** (optional)
5477** [ iojs+release] ( https://ci-release.nodejs.org/job/iojs+release/ ) ** can be used
5578to create a nightly release for the current _ HEAD_ if public test releases are
5679required. Builds triggered with this job are published straight to
5780< https://nodejs.org/download/nightly/ > and are available for public download.
5881
59- ** c .** ** Release builds:**
82+ ** d .** ** Release builds:**
6083** [ iojs+release] ( https://ci-release.nodejs.org/job/iojs+release/ ) ** does all of
6184the work to build all required release assets. Promotion of the release files is
6285a manual step once they are ready (see below).
@@ -66,8 +89,8 @@ this access to individuals authorized by the TSC.
6689
6790### 2. \< nodejs.org> access
6891
69- The _ dist_ user on nodejs.org controls the assets available in
70- < https://nodejs.org/download/ > . < https://nodejs.org/dist/ > is an alias for
92+ The _ dist_ user on the ` nodejs.org ` host controls the assets available in
93+ < https://nodejs.org/download/ > . < https://nodejs.org/dist/ > is an alias for
7194< https://nodejs.org/download/release/ > .
7295
7396The Jenkins release build workers upload their artifacts to the web server as
@@ -90,6 +113,12 @@ responsible for that release. In order to be able to verify downloaded binaries,
90113the public should be able to check that the ` SHASUMS256.txt ` file has been
91114signed by someone who has been authorized to create a release.
92115
116+ If you do not currently have a key then you should create one with a
117+ suitable strength with ` gpg --full-generate-key ` . The default options
118+ (currently "ECC sign and encrypt" and "Curve 25519") are good choices and
119+ consistent with the
120+ [ ssh key recommendations in the GOVERNANCE.md file] ( https://github.com/nodejs/Release/blob/main/GOVERNANCE.md#ssh-key-guidance ) .
121+
93122The public keys should be fetchable from a known third-party keyserver.
94123The OpenPGP keyserver at < https://keys.openpgp.org/ > is recommended.
95124Use the [ submission] ( https://keys.openpgp.org/upload ) form to submit
@@ -108,11 +137,30 @@ gpg --keyserver hkps://keys.openpgp.org --recv-keys <FINGERPRINT>
108137
109138The key you use may be a child/subkey of an existing key.
110139
140+ If you wish to also upload your key to the commonly used Ubuntu keyservers
141+ you can do so with
142+
143+ ``` bash
144+ gpg --keyserver keyserver.ubuntu.com --send-keys < FINGERPRINT>
145+ ```
146+
147+ and check it by switching the server name in the ` --recv-keys ` operation
148+ list above to the Ubuntu keyserver. For more information take a look at the
149+ [ Ubuntu GPG howto wiki page] ( https://help.ubuntu.com/community/GnuPrivacyGuardHowto ) .
150+
111151Additionally, full GPG key fingerprints for individuals authorized to release
112152should be listed in the Node.js GitHub README.md file.
113153
114- > It is recommended to sign all commits under the Node.js repository.
115- > Run: ` git config commit.gpgsign true ` inside the ` node ` folder.
154+ > All commits to branches in ` nodejs/node ` other than ` main ` and ` actions/* ` MUST be signed
155+ > otherwise pushing to those branches will be rejected by the GitHub rules
156+ > enforced by the Node.js project.
157+ > Run: ` git config commit.gpgsign true ` inside the ` node ` folder or use the
158+ > ` -S ` flag on your git operations (The examples in this document will
159+ > include ` -S ` expliticlty)
160+
161+ While GitHub allows signing individual commits using an ssh key,
162+ that is not covered here as this will not allow you to sign releases, so you
163+ will need to set up a GPG signing key in GitHub.
116164
117165## How to create a release
118166
@@ -123,7 +171,7 @@ Notes:
123171* Version strings are listed below as _ "vx.y.z"_ or _ "x.y.z"_ . Substitute for
124172 the release version.
125173* Examples will use the fictional release version ` 1.2.3 ` .
126- * When preparing a security release , follow the security steps in the details
174+ * When preparing a _ security release _ , follow the security steps in the details
127175 sections.
128176
129177### 0. Pre-release steps
@@ -136,13 +184,6 @@ and the release blog post is available on the project website.
136184Build can be contacted best by opening up an issue on the [ Build issue
137185tracker] [ ] .
138186
139- When preparing a security release, contact Build at least two weekdays in
140- advance of the expected release. To ensure that the security patch(es) can be
141- properly tested, run a ` node-test-pull-request ` job against the ` main ` branch
142- of the ` nodejs-private/node-private ` repository a day or so before the
143- [ CI lockdown procedure] [ ] begins. This is to confirm that Jenkins can properly
144- access the private repository.
145-
146187### 1. Update the staging branch
147188
148189Checkout the staging branch locally.
@@ -174,11 +215,11 @@ When landing the PR add the `Backport-PR-URL:` line to each commit. Close the
174215backport PR with ` Landed in ... ` . Update the label on the original PR from
175216` backport-requested-vN.x ` to ` backported-to-vN.x ` .
176217
177- You can add the ` Backport-PR-URL ` metadata by using ` --backport ` with
178- ` git node land `
218+ You can add the ` Backport-PR-URL ` metadata automatically when landing by
219+ using ` --backport ` with ` git node land ` :
179220
180221``` bash
181- git node land --backport $PR -NUMBER
222+ git node land -S - -backport $PR -NUMBER
182223```
183224
184225To determine the relevant commits, use
@@ -189,16 +230,32 @@ metadata, as well as the GitHub labels such as `semver-minor` and
189230omitted from a commit, the commit will show up because it's unsure if it's a
190231duplicate or not.
191232
233+ A ` branch-diff ` run can use a lot of credits and users are
234+ [ limited by default to 5000 per hour] ( https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2026-03-10 ) .
235+ It is not unusual for a run of branch-diff to
236+ use around 1000 of these. For this reason it is recommended that when you
237+ run branch-diff you redirect the output to a file and then process it. You
238+ can check your current usage with ` gh rate_limit ` if you have the GitHub CLI
239+ installed and configured, or using the curl command from
240+ [ this link] ( https://docs.github.com/en/rest/rate-limit/rate-limit?apiVersion=2026-03-10 )
241+ with authentication e.g.
242+
243+ ``` bash
244+ curl -H " Authorization: token $YOURGITHUBTOKEN " -X GET https://api.github.com/rate_limit
245+ ```
246+
192247For a list of commits that could be landed in a minor release on v1.x:
193248
194249``` bash
195250N=1 sh -c ' branch-diff v$N.x-staging upstream/main --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x --filter-release --format=simple'
196251```
197252
198- If the target branch is an LTS line, you should also exclude the ` baking-for-lts ` :
253+ If the target branch is an LTS line, you should also exclude the
254+ ` baking-for-lts ` and use a Current version released at least two weeks before the expected release date.
255+ In this example we use 25.5.0 as the base version to prepare a release for Node.js 24:
199256
200257``` bash
201- N=1 sh -c ' branch-diff v$N.x-staging upstream/main --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x,baking-for-lts --filter-release --format=simple'
258+ N=24 sh -c ' branch-diff v$N.x-staging v26.5.0 --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x,baking-for-lts --filter-release --format=simple'
202259```
203260
204261Previously released commits and version bumps do not need to be
@@ -216,6 +273,11 @@ Carefully review the list of commits:
216273When you are ready to cherry-pick commits, you can automate with the following
217274command.
218275
276+ Since this is slightly different from the previous branch-diff output - it
277+ contains only the commit SHAs and in revert order - you may wish to save
278+ this before piping it directly to ` git cherry-pick ` in case it does not go
279+ cleanly.
280+
219281``` bash
220282N=1 sh -c ' branch-diff v$N.x-staging upstream/main --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x --filter-release --format=sha --reverse' | xargs git cherry-pick -S
221283```
@@ -351,6 +413,8 @@ This will ensure they are included in the "Notable Changes" section of the CHANG
351413
352414### 3. Update ` src/node_version.h `
353415
416+ _ (This step will be done automatically if you are using ` create-release-proposal ` or ` git node release --prepare ` )_
417+
354418Set the version for the proposed release using the following macros, which are
355419already defined in ` src/node_version.h ` :
356420
@@ -369,6 +433,8 @@ be produced with a version string that does not have a trailing pre-release tag:
369433
370434### 4 . Update the changelog
371435
436+ _ (This step will be done automatically if you are using ` create-release-proposal ` or ` git node release --prepare ` )_
437+
372438#### Step 1: Collect the formatted list of changes
373439
374440Collect a formatted list of commits since the last release. Use
@@ -485,13 +551,15 @@ are formatted correctly.
485551If this release includes new APIs then it is necessary to document that they
486552were first added in this version. The relevant commits should already include
487553` REPLACEME ` tags (see [ Writing Documentation] ( ./api-documentation.md#writing-documentation ) ).
488- Check for these tags with
489554
490555``` bash
491556grep REPLACEME doc/api/* .md
492557```
493558
494- and substitute this node version with
559+ The above command will check for the presence of the tags and show you which
560+ files need to be updated. You can then perform the replacements with one of
561+ the following commands using either ` sed ` or ` perl ` . In these examples
562+ ` $VERSION ` must be prefixed with a ` v ` :
495563
496564``` bash
497565sed -i " s/REPLACEME/$VERSION /g" doc/api/* .md
509577perl -pi -e " s/REPLACEME/$VERSION /g" doc/api/* .md
510578```
511579
512- ` $VERSION ` should be prefixed with a ` v ` .
513-
514580If this release includes any new deprecations it is necessary to ensure that
515581those are assigned a proper static deprecation code. These are listed in the
516582docs (see ` doc/api/deprecations.md ` ) and in the source as ` DEP00XX ` . The code
520586
521587### 5. Create release commit
522588
589+ _ (This step will be done automatically if you are using ` create-release-proposal ` or ` git node release --prepare ` )_
590+
523591The ` CHANGELOG.md ` , ` doc/changelogs/CHANGELOG_Vx.md ` , ` src/node_version.h ` , and
524592` REPLACEME ` changes should be the final commit that will be tagged for the
525593release. When committing these to git, use the following message format:
@@ -561,6 +629,8 @@ Otherwise, you will leak the commits before the security release.
561629
562630### 6. Propose release on GitHub
563631
632+ _ (This step will be done automatically if you are using ` create-release-proposal ` or ` git node release --prepare ` )_
633+
564634Push the release branch to ` nodejs/node ` , not to your own fork. This allows
565635release branches to more easily be passed between members of the release team if
566636necessary.
@@ -612,13 +682,18 @@ purpose. Run it once with the base `vx.x` branch as a reference and with the
612682proposal branch to check if new regressions could be introduced in the
613683ecosystem.
614684
615- Use ` ncu-ci ` to compare ` vx.x ` run (10) and proposal branch (11)
685+ Use ` ncu-ci ` with the two build numbers from the ` citgm-smoker ` job to
686+ compare the base ` vx.x ` run (10) and the new proposal branch (11).
616687
617688``` bash
618689npm i -g @node-core/utils
619690ncu-ci citgm 10 11
620691```
621692
693+ A number of the modules tested by CitGM are not completely
694+ reliable so differences shown by the comparison are not immediately cause
695+ for concern.
696+
622697<details >
623698<summary >Security release</summary >
624699
@@ -744,7 +819,7 @@ Once you have produced builds that you're happy with you can either run
744819` git node release --promote ` :
745820
746821``` bash
747- git node release -- promote https://github.com/nodejs/node/pull/XXXX -S
822+ git node release -S -- promote https://github.com/nodejs/node/pull/XXXX
748823```
749824
750825to automate the remaining steps until step 16 or you can perform it manually
@@ -760,11 +835,10 @@ fetch the proposal from using the `--fetch-from` flag.
760835When promoting several releases, you can pass multiple URLs:
761836
762837``` bash
763- git node release --promote \
838+ git node release -S - -promote \
764839 --fetch-from git@github.com:nodejs-private/node-private.git \
765840 https://github.com/nodejs-private/node-private/pull/XXXX \
766- https://github.com/nodejs-private/node-private/pull/XXXX \
767- -S
841+ https://github.com/nodejs-private/node-private/pull/XXXX
768842```
769843
770844</details >
@@ -1494,7 +1568,6 @@ Typical resolution: sign the release again.
14941568```
14951569
14961570[ Build issue tracker ] : https://github.com/nodejs/build/issues/new
1497- [ CI lockdown procedure ] : https://github.com/nodejs/build/blob/HEAD/doc/jenkins-guide.md#restricting-access-for-security-releases
14981571[ Node.js Snap management repository ] : https://github.com/nodejs/snap
14991572[ Snap ] : https://snapcraft.io/node
15001573[ `create-release-post.yml` ] : https://github.com/nodejs/nodejs.org/actions/workflows/create-release-post.yml
0 commit comments