name: managing-prereleases
description: >-
How to optionally ship a major version of @confect/* as iterative Changesets
prereleases on a dedicated vN release branch before graduating to stable —
one possible release path for a major, not the only one. Use whenever the user
wants to cut a beta/next/prerelease, set up a vN branch, run pnpm changeset pre enter/pre exit, publish X.0.0-next.N versions under the npm next
dist-tag, or merge a prerelease line back into main.
Managing prereleases
A major version of @confect/* can be shipped as iterative prereleases on a dedicated vN branch under the npm next dist-tag, then graduated to stable when vN merges into main. This is one release path for a major, not a requirement — a major can also go straight out as a stable release from main like any other version. Reach for this workflow only when a major warrants a prerelease cycle (e.g. to let consumers try it under @next before it lands on latest).
For Changesets-specific behavior and caveats, see the upstream Changesets prereleases docs. Read them in full before your first prerelease cycle — the docs themselves open with: "Prereleases are very complicated! Using them requires a thorough understanding of all parts of npm publishes. Mistakes can lead to repository and publish states that are very hard to fix."
Conventions
- All
@confect/*packages version together via thefixedgroup in.changeset/config.json, so a singlepnpm changesetcovers every package being bumped for the major. - The release branch is named after the target major (
v9,v10, …).maincontinues to receive patch releases of the current stable line whilevNis in flight. - Prereleases publish through the existing
.github/workflows/release.yml, extended to trigger onvNalongsidemain. Do not add a separaterelease-vN.yml— npm trusted publishing (OIDC) is configured forrelease.yml, and a differently named workflow fails publish with a misleadingE404. - The Changesets
pretag isnext, which also becomes the npm dist-tag. Consumers opt in withpnpm add @confect/server@next;latestcontinues to resolve to the current stable line. pnpm release(defined in the rootpackage.json) ispnpm build && changeset publish. It works the same in pre mode and stable mode — the difference is purely in what.changeset/pre.json/ the changesets folder contain at publish time.
Never run prereleases on main
The upstream docs are explicit on this:
If you decide to do prereleases from the default branch of your repository, without having a branch for your last stable release without the prerelease changes, you will block other changes until you are ready to exit prerelease mode. We thoroughly recommend only running prereleases from a branch other than the default branch.
Always use a dedicated vN branch so main can keep cutting patch releases of the current stable line.
Caveats to keep in mind
These are from the Changesets docs but are easy to miss:
- Prerelease versions bump dependents more aggressively than stable releases. Most semver ranges do not satisfy prerelease versions (e.g.
^5.0.0is not satisfied by5.1.0-next.0), sochangeset versionwill bump packages depending on a prereleased package even when the dependent itself has no changeset. With the@confect/*fixed group this is mostly invisible, but expect every package in the group to move in lockstep on everynext.N. - New packages introduced during a prerelease cycle publish to the
latestdist-tag, notnext. A package being published for the first time always goes tolatest, and continues going tolatestfor subsequent prereleases until the cycle exits. If a brand-new@confect/foois added mid-cycle, its initial publish is not gated by@nextand will be visible to all consumers immediately. - Reuse
release.ymlfor vN publishes — never addrelease-vN.yml. npm trusted publishing matches on workflow filename. A separate workflow (e.g.release-v9.yml) will not match the trusted publisher entry forrelease.yml, and publish fails withE404rather than a clear auth error. Extend the existing workflow instead.
Entering prerelease mode
Create the release branch off
main.git switch main && git pull git switch -c v9Point
baseBranchat the release branch in.changeset/config.jsonsochangeset versioncompares against the right history:- "baseBranch": "main", + "baseBranch": "v9",Enter pre mode with the
nexttag. This creates.changeset/pre.json, which locks subsequentchangeset versionruns into producingX.0.0-next.Nand tags the npm publish withnext.pnpm changeset pre enter nextExtend
release.ymlto publish fromvN. Add the release branch to the existing workflow'spush.branches, pass the triggering branch tochangesets/action, and gate any stable-only post-publish steps (such as the docsreleasebranch push) tomainonly:on: push: branches: - main + - v9- uses: changesets/action@v1 with: publish: pnpm release - branch: main + branch: ${{ github.ref_name }}- name: Update docs deployment branch - if: steps.changesets.outputs.published == 'true' + if: steps.changesets.outputs.published == 'true' && github.ref_name == 'main'The prerelease cycle must not touch the docs
releasebranch — that tracks the stable line.Mirror the branch into the other CI workflows. Add
- v9to thepush.branchesandpull_request.brancheslists in any CI workflows that gatemain(typicallydocs.yml,example.yml,packages.yml) so PRs againstv9run the same checks as PRs againstmain.Commit and push.
git add .changeset/config.json .changeset/pre.json .github/workflows git commit -m "Enter v9 prerelease mode and extend release workflow" git push -u origin v9
After the push, changesets/action opens a Version Packages (next) PR against v9. From this point on, retarget every PR that should ship as part of the v9 line at v9 instead of main.
Publishing iterative prereleases
While .changeset/pre.json exists on v9:
- Author changesets normally with
pnpm changeseton feature branches targetingv9. Each merged PR is appended to the openVersion Packages (next)PR. - Merging the
Version Packages (next)PR bumps the nextX.0.0-next.Nand publishes under thenextdist-tag. - The merged changeset files are kept around — Changesets needs them to compose the final stable changelog on exit. Do not delete them manually.
There is no required cadence; ship as many next.Ns as the major needs.
Exiting prerelease mode
Exit pre mode and apply the final versions on the release branch. Both happen in a single commit, directly on
v9(no PR), matching the Changesets docs' recommended exit workflow.git switch v9 && git pull pnpm changeset pre exit pnpm changeset version pnpm format git add . git commit -m "Exit prerelease mode and version packages" git pushpre exitdeletes.changeset/pre.json.changeset versionthen consumes every changeset accumulated during the prerelease cycle and writes the final stable versions (e.g.9.0.0) into eachpackage.json. Runpnpm formatbefore committing —changeset versionwrites CHANGELOG entries in its own Markdown style, which fails the Format CI job otherwise. Pushing triggersrelease.yml; with no remaining changesets,changesets/actionskips opening a Version Packages PR and goes straight topnpm release, publishing the final stable tolatest.Open a PR merging
vNback intomainwith the major as the title (e.g.v9). Use a merge commit so the prerelease history is preserved inmain— merge commits are enabled repo-wide for exactly this case, even though squash is the norm for regular PRs. If the merge-commit option is missing from the UI (or the API returns405 Merge commits are not allowed), check that "Allow merge commits" is still enabled in the repository settings and that no "Require linear history" rule exists onmain— the rule overrides the repo-level toggle and hides the option.In a follow-up PR against
main, clean up the branch-specific machinery. Direct pushes tomainare disallowed, so branch offmainand open a PR. In one commit:- Revert
.changeset/config.jsonbaseBranchback tomain. - Remove
- v9frompush.branchesandpull_request.branchesin every workflow that referenced it (includingrelease.yml). release.ymlcontinues to publish stable frommainwith no further changes.
git switch main && git pull git switch -c cleanup-v9-machinery # edit configs as above git add .changeset/config.json .github/workflows git commit -m "Update \`v9\` branch references to \`main\`" git push -u origin cleanup-v9-machinery # open a PR against main and merge it once CI is green- Revert
Delete the release branch once
mainhas fully absorbed it.git push origin --delete v9 git branch -d v9
Quick reference
| Step | Command |
|---|---|
| Enter pre mode | pnpm changeset pre enter next |
| Author a changeset | pnpm changeset |
| Apply versions locally (the action normally does this) | pnpm changeset version |
| Exit pre mode | pnpm changeset pre exit |
| Publish manually (the action normally does this) | pnpm release |
| Install a prerelease | pnpm add @confect/server@next |