The release workflow
molt splits releasing into three verbs on two clocks: add records intent as you work, version consumes accumulated intent into concrete releases, and publish ships them.
If The changesets model explains why intent-based versioning works, this page explains how to run it day to day -- as a solo maintainer and as a team on a pull-request flow.
Three verbs
Two supporting verbs round it out: molt status shows what a release would contain, and any mutating command accepts --dry-run to print its plan without touching disk.
The two clocks
The idea that makes everything click is that adding intent and consuming intent run on two independent clocks.
- The development clock ticks once per meaningful change, driven by whoever wrote it. Ten pull requests over two weeks drop ten changesets into
.changeset/. - The release clock ticks whenever you decide to release.
molt versiondrains the whole.changeset/buffer at once and computes the correct version for every affected package.
Nobody has to pick a final version number when they open a pull request, because the number depends on everything that ships in the release -- which is not known until release time. A package with a pending minor and a pending patch moves once, by the higher bump. Three changesets do not mean three releases; they mean one release that reflects the most significant change, with all three summaries in the changelog.
The team flow: changesets in pull requests
On a team, the changeset is a reviewable artifact that travels with the code.
- A contributor opens a PR with their change and a changeset committed alongside it (
molt add). A reviewer can see at a glance that this PR intends, say, a minor bump toacme-core. - CI gates the PR with
molt status. It fails when a versionable package changed but no changeset was added -- a prompt to runmolt add, ormolt add --emptyif the change genuinely needs no release. - Changesets accumulate on the default branch as PRs merge. Nothing is released yet; intent is just piling up in
.changeset/. - A release job runs
molt versionand opens a "Version Packages" pull request containing the version bumps, changelog updates, and lockfile changes -- with the changesets consumed. This PR is the human-readable preview of the next release. - Merging that PR triggers
molt publish, which builds and uploads the changed packages and pushes their tags.
Steps 4 and 5 are wired up for you by the GitHub Action; the same shape works on any forge, since the forge is a seam.
When to use --dry-run
Every mutating command -- add, version, publish, build, git-tag -- can build its plan and print it without executing. Reach for --dry-run when you want to look before you leap:
- Before a release,
molt version --dry-runshows every version bump and file it would write.molt statusanswers the same question and is the read-only, CI-friendly form. - Before publishing,
molt publish --dry-runshows exactly which packages and versions would be uploaded, and in what order. - In CI or a script, pass
--output jsonto get the plan as a machine-readable object you can gate on.
Because the plan is the same value molt would otherwise execute, a dry run is a faithful preview, not an approximation.
A note on exit codes
molt's exit codes are designed for CI, and a couple are worth internalizing:
molt versionexits 1 when there are no pending changesets. There is nothing to release, and that is treated as a failure so a misconfigured pipeline does not silently "succeed".molt statusexits 1 when a package changed but no changeset covers it (the CI gate above), and 0 when there is genuinely nothing to release.molt publishexits 0 when there is nothing new to upload.
The full contract is in the CLI overview.
Where to go next
- Adding a changeset -- interactive and non-interactive
molt add. - Versioning -- everything
molt versiondoes, and how to preview it. - CI: GitHub Action -- automate steps 4 and 5.
- Dry runs and plans -- the plan object behind every command.