This document assumes you use version generation mode "conventional commits" or "version bump". "explicit version" does not provide any help with respect to prerelease versions, all you get is just floating tags
Prereleases allow to evolve a version -alfa.1..N → -beta.1..N → -rc.1..N while staying in the same branch!
Branch. First, create a branch. next is a recommended branch name because it is not tied to any specific suffix
and allows to change it as your software gets more stable
Configure GitHub workflow (e.g. .github/workflows/release.yaml) to trigger on this branch:
on:
push:
branches:
- main
- nextConfiguration. Configure the branch as prerelease: set branch property prerelease in .releaserc.json file (recommended) or via release-branches input
This property can be true or a string like alpha, beta, rc etc.
prerelease: truemeans "use branch name as version suffix", ex:nextbranch →2.0.0-next.1prerelease: <suffix>means "use as version suffix", ex:prerelease: "alpha"→2.0.0-alpha.1
Additionally, you can use property channel for floating tags
First commit is very important — it defines a version you intend to release at the end.
Most of the time prerelease is used to start work on a new major version,
so the first commit in next branch should start from feat!: ..
Assume you made branch next from main at version 1.2.3
- "conventional commits" mode with commit
feat!: ..will create version2.0.0-next.1 - "conventional commits" mode with commit
feat: ..will create version1.3.0-next.1 - "conventional commits" mode with commit
fix: ..will create version1.2.4-next.1 - "version bump" mode with
default-patchwill create version1.2.4-next.0 - "version bump" mode with
default-minorwill create version1.3.0-next.0Note: if you use "version bump" mode and want a next major version, in the first commit you must follow "conventional commits" rules
Next table shows behavior with first major commit and different combinations of prerelease and channel:
| branch | version | prerelease | channel | version | git tags | Docker tags and S3 dirs | npm tag | |
|---|---|---|---|---|---|---|---|---|
next |
1.2.3 | true | ⇒ | 2.0.0-next.1 |
2.0.0-next.1 |
same | next |
|
next |
1.2.3 | true | false | ⇒ | 2.0.0-next.1 |
2.0.0-next.1 |
same | next |
next |
1.2.3 | true | next | ⇒ | 2.0.0-next.1 |
2.0.0-next.1 |
2.0.0-next.2, next |
next |
next |
1.2.3 | true | beta | ⇒ | 2.0.0-next.1 |
2.0.0-next.1, beta |
same | next |
next |
1.2.3 | alpha | ⇒ | 2.0.0-alpha.1 |
2.0.0-alpha.2 |
same | next |
|
next |
1.2.3 | alpha | false | ⇒ | 2.0.0-alpha.1 |
2.0.0-alpha.2 |
same | next |
next |
1.2.3 | alpha | next | ⇒ | 2.0.0-alpha.1 |
2.0.0-alpha.2 |
2.0.0-alpha.2, next |
next |
next |
1.2.3 | alpha | beta | ⇒ | 2.0.0-alpha.1 |
2.0.0-alpha.2, beta |
same | next |
Subsequent commits. No matter what commit message you make (fix:, feat: etc.) or "version bump" default-patch/default-minor you use,
the version will always be incremented +1 in the prerelease sequence: 2.0.0-alpha.1 → 2.0.0-alpha.2.
In case of "conventional commits", the commit messages still matter: they're used to generate GitHub releases.
Also, once you finally merge prerelease branch → main, then all conventional commits will be reflected in a CHANGELOG.md file
Merge to main. Use merge commit. Do not use rebase because last commit in next has [skip ci] tag,
so release workflow will not be triggered on main.
Do not use squash because you will lose all conventional commits in the prerelease branch!
Given branch main with current version 2.4.0. Create branch next with following .releaserc.json:
{
"branches": [
"main",
{
"name": "next",
"prerelease": "alpha",
"channel": "demo"
}
]
}In the table below each row represents a commit in the next branch:
| branch | version | prerelease | channel | commit | version | git tags | Docker tags and S3 dirs | npm tag | |
|---|---|---|---|---|---|---|---|---|---|
next |
2.4.0 | alpha | demo | BR CH: | ⇒ | 3.0.0-alpha.1 |
3.0.0-alpha.1, demo |
same | demo |
next |
3.0.0-alpha.1 | alpha | demo | fix: | ⇒ | 3.0.0-alpha.2 |
3.0.0-alpha.2, demo |
same | demo |
next |
3.0.0-alpha.2 | beta | demo | feat: | ⇒ | 3.0.0-beta.1 |
3.0.0-beta.1, demo |
same | demo |
next |
3.0.0-beta.1 | beta | demo | fix: | ⇒ | 3.0.0-beta.2 |
3.0.0-beta.2, demo |
same | demo |
next |
3.0.0-beta.2 | rc | feat: | ⇒ | 3.0.0-rc.1 |
3.0.0-rc.1 |
same | next |
|
next |
3.0.0-rc.1 | rc | fix: | ⇒ | 3.0.0-rc.2 |
3.0.0-rc.2 |
same | next |
Rules:
- change of
prereleasedrops number back to 1, so3.0.0-alpha.2becomes3.0.0-beta.1 channelshould not be changed in the middle of prerelease sequence- explicit
channelgives a floating tag
Read more about prerelease branches in semantic-release documentation