Strategies
A strategy (the release-type config key) tells Versionary how to read and write a project's version, what to validate, and which changelog format to prefer. The version bump itself comes from Conventional Commits and is the same across all strategies—the strategy only governs where the version lives and which files get updated.
release-type | Version source | Default changelog | Notes |
|---|---|---|---|
simple | version.txt | CHANGELOG.md | Plain text. The default. |
node | package.json | CHANGELOG.md | Syncs npm lockfiles. |
rust | Cargo.toml | CHANGELOG.md | Workspace inheritance, internal deps, Cargo.lock. |
python | pyproject.toml | CHANGELOG.md | Or a .py __version__ file; refreshes lockfiles. |
r | DESCRIPTION | NEWS.md | Uses the r-news changelog format. |
julia | Project.toml | CHANGELOG.md | Root-level version. |
latex | build.lua | CHANGELOG.md | Also updates .dtx package metadata. |
For polyglot projects, release-type can be an array to compose strategies.
The version file can be overridden per project (or per package) with the version-file config key, with the strategy-specific exceptions noted below.
simple
The default when release-type is omitted.
- Version source:
version.txt(override withversion-file). - Reads/writes: the trimmed contents of the file; writes
version\n. - No dependency management, no lockfiles. Ideal for docs sites, non-standard projects, or anything without a language manifest.
node
- Version source:
package.jsonversionfield. - Package name:
package.jsonname(used for monorepo tag naming). - Lockfiles: when present,
package-lock.jsonandnpm-shrinkwrap.jsonare updated to the new version in the same write. - Changelog:
markdown-changelog.
rust
- Version source:
Cargo.toml[package].version.version-filemust point at aCargo.toml. - Package name:
Cargo.toml[package].name. - Workspaces: virtual/workspace manifests expand to their members. Crates using
version.workspace = trueresolve and update[workspace.package].versionin the owning workspace manifest. - Internal dependencies: when a dependency name matches another targeted crate, its version requirement is rewritten across
[dependencies],[dev-dependencies],[build-dependencies], and their[target.*]variants. Operators (^,~,>=, …) and table vs. string forms are preserved. - Lockfiles:
Cargo.lockfiles are refreshed viacargo generate-lockfile.cargomust be onPATHduring PR preparation when aCargo.lockexists. - Changelog:
markdown-changelog.
Not done (by design): external dependency updates, workspace.dependencies updates, adding missing version fields to dependency tables, or publishing to crates.io.
python
- Version source:
pyproject.tomlby default. Versionary updates[project].versionand/or[tool.poetry].version—whichever are present. - Source-file mode: point
version-fileat a Python file (e.g.src/<pkg>/__init__.py) to update a__version__ = "X.Y.Z"assignment instead of the TOML. __init__.pydiscovery: when usingpyproject.toml, a matching__init__.pywith__version__in standard locations is also updated.- Package name:
[project].name, falling back to[tool.poetry].name. - Lockfiles:
poetry.lock,uv.lock, andpdm.lockat the package root are refreshed by shelling out to the matching tool (poetry lock --no-update,uv lock,pdm lock --update-reuse). The corresponding binary must be onPATH. - Changelog:
markdown-changelog.
r
- Version source:
DESCRIPTIONVersion:field. - Package name:
DESCRIPTIONPackage:field. - Changelog: defaults to
NEWS.mdwith ther-newsformat, which follows R package conventions (single-#version headings, abbreviatedmajor.minorheadings, and extraction of an "unreleased"/development notes block at the top ofNEWS.md). - Updates are performed by targeted replacement of the
Version:line.
julia
- Version source:
Project.toml, the root-levelversionfield (Julia keepsname/versionas root keys, not under a[table]). - The update is line-based to preserve formatting, comments, quote style, and line endings; it stops searching at the first table header.
- Changelog:
markdown-changelog.
latex
- Version source:
build.lua(theversion = "X.Y.Z"assignment). .dtxmetadata: during finalization, every.dtxfile undersrc/is updated. Versionary rewrites the package metadata using the release commit date:\ProvidesPackage{name}[YYYY-MM-DD vX.Y.Z description]\ProvidesExplPackage{name}{YYYY-MM-DD}{X.Y.Z}{description}Each.dtxmust contain exactly one such entry, andsrc/must contain at least one.dtxfile.
- Changelog:
markdown-changelog.
Composite strategies
Set release-type to an array to update multiple manifests with the same version—useful for projects that carry more than one language manifest:
{
"version": 1,
"release-type": ["python", "rust"]
}Semantics:
- The first entry is the primary. It drives
readVersion,readPackageName, and consumes anyversion-fileoverride. - Each subsequent entry is a secondary and writes its own default manifest to the same target version (secondaries do not see the primary's
version-fileoverride). - Validation, dependency-impact propagation, and finalization run across all strategies; the changelog format comes from the primary.
Common combinations:
["python", "rust"]— PyO3/maturin (pyproject.toml+Cargo.toml+Cargo.lock)["node", "rust"]— napi-rs (package.json+Cargo.toml+Cargo.lock)["r", "rust"]— R packages with embedded Rust crates
WARNING
The array form does not yet support nested manifests at non-default paths (e.g. an R package's src/rust/Cargo.toml). Until per-strategy version-file overrides land, use a single strategy for those layouts.
Auto-detection
Strategies are selected explicitly via release-type; there is no silent auto-detection by language. However, versionary verify validates that the configured strategy's version file exists and parses, so a misconfigured release-type is caught early.