Configuration reference
Verso reads verso.toml from the current directory unless --config <PATH> or --group <NAME> is
supplied. --config accepts a relative or absolute file path, while --group core selects
verso.core.toml. The selected file's directory becomes the release root: package patterns,
manifests, changelog, hooks, and Git commands all resolve from there.
Unknown tables and keys are rejected. Paths and patterns written inside verso.toml must be relative
to the release root, use forward slashes, and cannot contain parent-directory (..) segments.
Default configuration
[version]root_package = "package.json"require_consistent_versions = truecargo_manifest_paths = [][workspaces]patterns = []include_root = trueignore = []use_gitignore = true[changelog]enabled = falseinfile = "CHANGELOG.md"preset = "angular"[git]require_clean_worktree = truecommit_message = "chore(release): release v${version}"tag_name = "v${version}"push = "atomic"[hooks]# before_version = "pnpm test"# after_version = "pnpm build"# before_commit = "pnpm lint"# after_commit = "node scripts/verify-release.mjs"# before_tag = "pnpm pack"# after_tag = "node scripts/record-tag.mjs"# before_push = "pnpm check"# after_push = "node scripts/notify.mjs"Every table and key is optional. When the default config path is absent and a root package manifest exists, Verso uses these values without creating a file. An explicitly supplied missing config is always an error.
Workspace discovery
When workspaces.patterns is empty, Verso first reads packages from pnpm-workspace.yaml, then the
root manifest's workspaces field. If neither defines patterns, only the root package is used.
| Key | Default | Behavior |
|---|---|---|
patterns | [] | Include globs; supports *, **, ?, character classes, braces, and leading ! exclusions |
include_root | true | Include the manifest selected by version.root_package |
ignore | [] | Exclude matching paths; a plain segment such as fixtures excludes that directory name anywhere |
use_gitignore | true | Honor root and nested .gitignore files while walking |
node_modules and .git are always excluded. If include_root = false, patterns must be explicit
and nonempty; inferred workspace patterns are not accepted for that combination.
Set include_root = false when the root manifest only describes the workspace and should not share
the release group's version.
Each matched directory contributes the first existing manifest in this order:
package.json, package.json5, package.yaml, package.yml. Verso changes only the top-level
version scalar and preserves the rest of the file's formatting.
Version sources
| Key | Default | Behavior |
|---|---|---|
root_package | package.json | Provides the current version and joins the update when include_root is enabled |
require_consistent_versions | true | Must remain true; rejects members whose versions differ so the group has one current version |
cargo_manifest_paths | [] | Updates each manifest's [package].version and its nearest ancestor Cargo.lock, when present |
When the default root_package does not exist, Verso may resolve another supported manifest in the
release root. A custom root_package is used exactly as configured.
Release groups
One config defines one release group. Every package and configured Cargo manifest discovered by that
config receives the same target version. version.require_consistent_versions must remain true;
setting it to false is rejected because it would make the group's current version ambiguous.
Use separate configs for independently versioned groups and run one group at a time:
verso.core.toml -> verso --group core bump minorverso.ui.toml -> verso --group ui --version 2.0.0 --yesFor a named group, the default v${version} template is automatically scoped with the group name:
core-v1.2.3, ui-v1.2.3, and so on. An explicitly different git.tag_name is used unchanged.
--group <NAME> and --config <PATH> are mutually exclusive. Group names start with an ASCII letter
or digit and may otherwise contain ASCII letters, digits, -, and _.
Changelog
Set changelog.enabled = true to add a release entry to changelog.infile. changelog.preset
accepts angular and keep-a-changelog. Changelog generation runs only for a full release;
verso bump leaves the file unchanged.
For either preset, Verso finds the highest reachable SemVer tag matching git.tag_name, reads
non-merge commits after it, and classifies Conventional Commit subjects. The angular preset uses:
fix-> Bug Fixesfeat-> Featuresperf-> Performance Improvements!or aBREAKING CHANGE:footer -> BREAKING CHANGES- other conventional types -> a type-specific Other Changes section
- non-conventional commits -> omitted
GitHub compare, commit, and issue links are added when the origin remote is a recognized GitHub
SSH or HTTPS URL. An empty classified set produces No classifiable changes.
The keep-a-changelog preset inserts each release immediately after ## [Unreleased] and maps
feat to Added, fix to Fixed, and performance, breaking, and other conventional changes to Changed.
It also updates the [Unreleased] and release link definitions when a GitHub origin is available.
Git policy
| Key | Default | Behavior |
|---|---|---|
require_clean_worktree | true | Requires git status --porcelain to be empty before writes |
commit_message | chore(release): release v${version} | Replaces every ${version} placeholder with the target |
tag_name | v${version} | Must contain ${version}; named groups scope this default with the group name |
push | atomic | Pushes the current upstream branch and exact release tag in one atomic command |
With require_clean_worktree = false, unrelated unstaged files are allowed, but the index and every
release file must still be clean. No non-atomic push mode exists.
Hooks are trusted shell commands
Hooks run from the release root through sh -c on macOS/Linux and cmd /C on Windows. Empty strings
are treated as disabled. A nonzero exit stops the release at that stage.
verso bump runs only before_version and after_version; commit, tag, and push hooks belong to a
full release.