Configuration
Versionary reads configuration from versionary.jsonc (preferred) or versionary.json at the repository root. These are the only supported filenames. The schema is strict—unknown keys are rejected.
Editor support
Add a $schema reference for autocomplete and validation:
{
"$schema": "https://raw.githubusercontent.com/jolars/versionary/main/schemas/config.json",
"version": 1,
"release-type": "node"
}The published schema is generated from Versionary's internal Zod schema, which is the single source of truth for the config shape.
Top-level keys
| Key | Type | Default | Description |
|---|---|---|---|
version | 1 | — (required) | Config-format version. Must be 1. |
$schema | string | — | JSON Schema URL for editor support. |
release-type | string | string[] | "simple" | The strategy (or array of strategies) used to read/write versions. |
review-mode | "direct" | "pr" | "pr" | Release style. pr opens a release PR; direct commits to the triggering branch and publishes in one run. See workflows. |
release-pr-checks | "run" | "skip" | "run" | Whether the CI integration runs checks on Versionary release PRs. Requires workflow integration. |
release-mode | "versionary" | "external" | "versionary" | Who creates tags and release metadata. external emits the merged commit and notes, then waits for downstream tags. See Julia packages. |
version-file | string | strategy-specific | Path to the primary version source. Default depends on release-type (see table below). |
changelog-file | string | CHANGELOG.md / NEWS.md | Path to the changelog. Defaults to NEWS.md for the R strategy, CHANGELOG.md otherwise. |
changelog-format | "markdown-changelog" | "r-news" | strategy-specific | Changelog format. Defaults to r-news for the R strategy, markdown-changelog otherwise. |
release-branch | string | "versionary/release" | Branch used for the release PR/commit and prefix for separate package PRs. See selective CI. |
separate-release-prs | boolean | false | Open an independent release PR for each releasable package or coupled package cohort. See monorepos. |
baseline-file | string | ".versionary-manifest.json" | File tracking the baseline SHA for deterministic commit ranges. |
bootstrap-sha | string | — | First-run baseline commit when adopting Versionary on existing history. |
release-draft | boolean | false | Publish GitHub Releases as drafts. |
release-latest | boolean | true for root; false otherwise | Request GitHub Latest promotion for new releases. See inheritance. |
release-reference-comments | "off" | "best-effort" | "strict" | "off" | Whether to comment on linked issues/PRs when released. See below. |
monorepo-mode | "independent" | "fixed" | — | Enables monorepo planning. |
packages | object | — | Per-package configuration (see packages). |
allow-stable-major | boolean | false | Allow a breaking 0.y.z release to become 1.0.0. See pre-1.0 policy. |
exclude-paths | string[] | — | Glob/path prefixes whose changes don't, on their own, count toward a bump. Applies repo-wide and to every package. |
commit-overrides | object | — | Exclusions or replacement messages keyed by full commit SHA. See commit overrides. |
include-commit-authors | boolean | — | Accepted by the schema; not yet wired into changelog rendering. |
release-pr-checks
Set "skip" to let Versionary's CI integration skip expensive checks on its release PRs. The default, "run", keeps checks enabled. This is a repository-wide policy shared by combined release PRs and separate package or cohort PRs.
The setting takes effect through versionary ci --json or the Action's command: ci mode. Wire build, test, and lint jobs to the decision's run_checks output using the workflow recipe. Adding the setting alone does not change GitHub's workflow rules.
Versionary skips checks only when the event identifies a release branch in the same repository. Ordinary PRs, fork PRs, pushes after merging, and unknown event contexts keep checks enabled. Direct release mode always runs checks. Invalid configuration fails the decision command rather than producing a skip result.
commit-overrides
Correct release metadata for commits that have already landed without rewriting Git history. Each key is a full, lowercase commit SHA. Each value contains either skip: true or a message, plus an optional reason:
{
"version": 1,
"commit-overrides": {
"0123456789abcdef0123456789abcdef01234567": {
"skip": true,
"reason": "Fixes a regression introduced after the previous release"
},
"89abcdef0123456789abcdef0123456789abcdef": {
"message": "perf: cache commit lookups",
"reason": "The original commit was incorrectly labeled feat"
}
}
}skip: true excludes the commit from both version calculation and generated release notes, including any Release-As footer. Its code still ships. message replaces the complete message used for release analysis and notes, including the body and footers. Include any breaking markers or issue references that should remain. The replacement must be a valid Conventional Commit. Versionary preserves the original SHA and uses the original changed files to attribute the commit to packages. Existing suppression of revert pairs still uses the original commit relationships.
Overrides apply only within each package's unreleased commit window. They do not change earlier releases. Configured SHAs must resolve to commits in the current branch's history. versionary plan includes a commitOverrides array with the original messages, overrides, reasons, and package paths where they still apply. An empty packages array means the override has been consumed.
The exclude and correct commands accept short SHAs and write these entries while preserving JSONC comments. Commit the configuration change so local planning and CI use the same metadata. To undo an override before release, remove its entry.
Versionary removes consumed entries during a later release's preparation. In a monorepo, it retains an entry while any configured package still has the commit in its release window. Cleanup does not require unrelated package release PRs to merge together.
Deprecated: bump-minor-pre-major
bump-minor-pre-major remains accepted at the repository root and package level for compatibility with Versionary 1.3.0. Versionary warns when it is used and immediately normalizes it to allow-stable-major:
bump-minor-pre-major: truebecomesallow-stable-major: false.bump-minor-pre-major: falsebecomesallow-stable-major: true.
Replace the deprecated key with the corresponding canonical value. Do not configure both keys in the same object; Versionary rejects that ambiguity.
release-reference-comments
Controls comments posted on issues/PRs referenced by released commits:
off(default) — don't post comments.best-effort— post comments, but continue if the API call fails (e.g. missing permissions).strict— fail the release if a comment can't be posted.
Comments require issues: write permission and are authored by the account that owns the configured token. The comment body itself is signed by Versionary.
Default version files by strategy
release-type | Default version-file |
|---|---|
simple | version.txt |
cmake | CMakeLists.txt |
node | package.json |
rust | Cargo.toml |
r | DESCRIPTION |
python | pyproject.toml |
julia | Project.toml |
latex | build.lua |
See Strategies for the full behavior of each.
packages
A map keyed by package path ("." for the repository root). Used with monorepo-mode. Each entry inherits the top-level config and may override:
| Key | Type | Description |
|---|---|---|
release-type | string | string[] | Strategy for this package, overriding the top-level value. |
package-name | string | Override the release/tag name (otherwise derived from the version file or path). |
changelog-file | string | Package-specific changelog path (written under the package directory). |
changelog-format | "markdown-changelog" | "r-news" | Package-specific changelog format. |
allow-stable-major | boolean | Override the pre-1.0 policy for this package's own bump. |
exclude-paths | string[] | Paths (relative to the package) to exclude; unioned with the top-level list. |
follows | string[] | Source packages this package follows; see follows. |
extra-files | artifact-rule[] | Additional files to update with the new version (see below). |
release-draft | boolean | Override whether this package's GitHub Release is created as a draft. |
release-latest | boolean | Override whether this package's new GitHub Release requests Latest promotion. |
See the monorepos guide for tag naming, follows, and filtering semantics.
release-draft
Package-level release-draft values override the top-level setting. Packages that omit the key inherit the top-level value; if neither level sets it, Versionary creates a non-draft release. An explicitly configured root package at "." follows the same rule.
This allows packages with different publication gates to share one monorepo configuration:
{
"version": 1,
"release-type": "simple",
"monorepo-mode": "independent",
"separate-release-prs": true,
"release-draft": false,
"packages": {
"packages/python": {
"release-type": "python"
},
"packages/r": {
"release-type": "r",
"release-draft": true
},
"packages/julia": {
"release-type": "julia",
"release-draft": true
}
}
}Here, the Python package inherits false, while the R and Julia packages create draft GitHub Releases. Draft selection does not change package grouping or release PR planning.
release-latest
Controls whether a new GitHub Release requests Latest promotion. The setting applies in both PR and direct release workflows. Versionary resolves it for each release target in this order:
- The package's
release-latest, including an explicit root package at".". - The top-level
release-latest. truefor the root package andfalsefor other packages.
An explicit false overrides an inherited true. For example, this configuration promotes only the root package's releases:
{
"version": 1,
"release-type": "node",
"monorepo-mode": "independent",
"release-latest": false,
"packages": {
".": { "release-latest": true },
"packages/helper": {}
}
}GitHub has one Latest release per repository. Setting the top-level value to true makes every inheriting package request promotion, so use package overrides when only one package should hold that designation. GitHub does not allow drafts or prereleases to become Latest.
For a maintenance branch, set release-latest: false to keep its releases from replacing the current line's Latest release. This setting does not change version calculation or mark a release as a prerelease. Registry publishing and website deployment use their own policies.
Retries apply the configured policy when creating missing release metadata. Existing GitHub Releases are reused without changing their metadata, so changing this setting does not retroactively promote or demote an existing release.
extra-files
extra-files (per package) updates additional files to the new version. Each rule is an artifact rule:
| Field | Type | Applies to | Description |
|---|---|---|---|
type | enum | all | One of json, toml, yaml, nix, regex. |
path | string | all | Path to the file to update. |
field-path | string | json/toml/yaml/nix | JSONPath-style locator of the version field (e.g. $.version). Required for these types. |
pattern | string | regex | Regex with a capturing group (or a named (?<version>…) group) around the version. Required for regex. |
replacement | string | regex | Optional template for the substituted text. When set, the entire match is replaced with the rendered template. |
expected-matches | positive integer | regex | Exact number of occurrences the pattern must match. Defaults to 1. |
Validation rules enforced by the schema:
json/toml/yaml/nixrules requirefield-pathand must not usepatternorreplacement.regexrules requirepatternand must not usefield-path.expected-matchesis available only forregexrules and must be a positive integer.
Regex substitution
Without a replacement, the first capturing group is replaced with the full computed version, leaving the rest of the match intact. This keeps a full [email protected]-style reference in sync.
By default, the pattern must match exactly once. Set expected-matches when a file intentionally contains several occurrences. Versionary updates every match and aborts if the actual count differs, guarding against missing or overly broad matches.
With a replacement, the whole match is replaced by the rendered template. The following placeholders are available:
| Token | Value |
|---|---|
| the full computed version (1.2.3) |
| the major component (1) |
| the minor component (2) |
| the patch component (3) |
| dot-joined prerelease identifiers |
| dot-joined build-metadata identifiers |
This is useful for major-only references such as a moving @v1 tag, which should only advance on a major release:
{
"type": "regex",
"path": "README.md",
"pattern": "jolars/panache-action@v(\\d+)",
"replacement": "jolars/panache-action@v{{major}}"
}On a 2.0.0 release this rewrites @v1 to @v2 (not @v2.0.0).
Example — keep the action's pinned version in sync, plus a TOML manifest:
{
"version": 1,
"release-type": "node",
"packages": {
".": {
"extra-files": [
{
"type": "yaml",
"path": "action.yml",
"field-path": "$.inputs.versionary-version.default"
},
{
"type": "regex",
"path": "README.md",
"pattern": "versionary@(?<version>\\d+\\.\\d+\\.\\d+)"
}
]
}
}
}Validation errors
packages with follows are validated at load time. The following are configuration errors:
- a package following itself
- following an unknown package path
followscycles (reported with the offending chain)- combining
followswithmonorepo-mode: "fixed" - enabling
separate-release-prswithout a non-emptypackagesmap - combining
separate-release-prswithmonorepo-mode: "fixed"orreview-mode: "direct"
Run versionary verify to check your config and version files before relying on them in CI.