Configuration
Releasaurus works with zero configuration for changelog generation and
tagging. Add an optional releasaurus.toml at your repository root when
you need more. This page covers the common cases; for the exhaustive
option list see the Configuration Reference.
Do You Need a Config File?
You don’t need one if you only want changelog generation and tagging
with the default format and the default v tag prefix.
You do need one to:
- update version files (set a
release_type) - manage multiple packages (monorepo)
- create prereleases (alpha/beta/rc/snapshot)
- customize the changelog or use custom tag prefixes
Place the file at the repository root:
my-project/
├── releasaurus.toml
├── src/
└── README.md
Config is organized under three top-level tables:
[repository]— repo-wide settings (base branch, search depths, combined vs. separate PRs, and commit modifiers —skip_shas/reword).[defaults]— release defaults for every package, split into[defaults.versioning](what affects the computed version, including commit filtering and grouping) and[defaults.changelog](how the changelog is rendered). Most keys can be overridden per package.[[package]]— one entry per independently-versioned package.
See the Configuration Reference for every key.
Single Package
The most common setup — bump versions in one package’s manifests:
[[package]]
path = "."
release_type = "node" # or rust, python, java, php, ruby, go, generic
release_type selects which manifest and lock files are updated. See
Supported Languages
for the file list per language.
Monorepos
Define one [[package]] per independently-versioned package. Each gets
its own version, tag prefix, and manifest updates.
[[package]]
path = "./frontend"
release_type = "node"
tag_prefix = "frontend-v"
[[package]]
path = "./backend"
release_type = "rust"
tag_prefix = "backend-v"
Tag prefix defaults to v for a root package (path = ".") and
<name>-v for nested packages.
Combined vs. Separate PRs
By default all packages with changes are released in a single PR. Set
separate_pull_requests = true under [repository] to give each package
its own PR (branches like releasaurus-release-main-frontend):
[repository]
separate_pull_requests = true
[[package]]
path = "./frontend"
release_type = "node"
tag_prefix = "frontend-v"
[[package]]
path = "./backend"
release_type = "rust"
tag_prefix = "backend-v"
- Combined (default) — best for tightly-coupled packages that release together and a single, atomic review.
- Separate — best for large monorepos and independently-versioned packages with different release cadences or owners.
In either mode, target one package with --package <name> on release-pr
and release.
Commit Message & PR Title Templates
The release commit message and the PR title are Tera templates. By default they match:
chore(main): release my-package v1.2.3 # one package, or separate PRs
chore(main): release my-repo # combined PR, multiple packages
A PR that covers a single package can name that package and its version; one that covers several can’t. So there are two sets of templates, and which set applies is fixed by your config rather than by what changed:
| Your config | Commit message | PR title |
|---|---|---|
separate_pull_requests = true | commit_message_template | pr_title_template |
One [[package]] | commit_message_template | pr_title_template |
Multiple [[package]] and separate_pull_requests = false | monorepo_commit_message_template | monorepo_pr_title_template |
Each package gets its own PR under separate_pull_requests = true, and a
single-package repo only ever has one, so both cases can use the
per-package pair. A combined PR across multiple packages uses the
monorepo_* pair.
Only top-level [[package]] entries count. A single package with
sub-packages is still one package, since
sub-packages share their parent’s PR and tag.
Because the choice comes from your config, a multi-package repo with
separate_pull_requests = falseuses themonorepo_*pair on every run — including runs where only one package changed, and including--package <name>. That keeps the format predictable, at the cost of those PRs not naming the package. Useseparate_pull_requests = trueif you want every PR titled after its package.
Set them under [defaults], and override the per-package pair on
individual packages:
[defaults]
commit_message_template = "chore({{ branch }}): release {{ package_name }} {{ semver }}"
pr_title_template = "🚀 Release {{ package_name }} {{ tag }}"
monorepo_commit_message_template = "chore({{ branch }}): release {{ repo_name }}"
monorepo_pr_title_template = "🚀 Release {{ repo_name }}"
[[package]]
name = "frontend"
path = "./apps/web"
release_type = "node"
# This package alone gets a ticket-scoped commit and a plainer title.
commit_message_template = "chore(web): release {{ tag }} [skip ci]"
pr_title_template = "Web release {{ tag }}"
Variables
Available in all four templates:
| Variable | Description | Example |
|---|---|---|
branch | The base branch being released to | main |
repo_name | Repository name | my-repo |
Available in commit_message_template and pr_title_template only,
because a PR spanning several packages has no single one of these:
| Variable | Description | Example |
|---|---|---|
package_name | Name of the package being released | frontend |
tag | Full tag, including the tag prefix | web-v1.2.3 |
semver | Version alone, without the prefix | 1.2.3 |
Referencing a variable that isn’t in scope is an error, and it’s caught
when the config loads rather than partway through a release — so
monorepo_pr_title_template = "{{ package_name }}" fails before anything
is pushed.
Filters work as they do in the changelog body template, so you can
reshape a value rather than needing a variable for every form of it:
[defaults]
pr_title_template = "Release {{ package_name | upper }} {{ tag }}"
Tracking Shared Code
Use additional_paths so a package also releases when shared directories
change:
[[package]]
path = "./apps/web"
release_type = "node"
tag_prefix = "web-v"
additional_paths = ["shared/types", "shared/utils"]
Workspaces in a Subdirectory
When a workspace isn’t at the repo root, set workspace_root so lock
files resolve correctly:
[[package]]
name = "api-server"
workspace_root = "backend"
path = "services/api"
release_type = "rust"
tag_prefix = "api-v"
This updates backend/services/api/Cargo.toml and the workspace
backend/Cargo.lock.
Naming & Path Rules
- Names must be unique across all packages. If omitted, the name is
derived from the last path component. Match the manifest’s
namefield where one exists (package.json,Cargo.toml, etc.). - The full path (
workspace_root+path) must be unique. Two packages may share apathonly if theirworkspace_rootdiffers. - Sub-packages count for both rules. A sub-package name or full path
may not repeat one used by any other package or sub-package anywhere in
the config. Names key dependency entries in lock files, and two entries
on one path would both write the same
CHANGELOG.md.
Grouped Releases (Sub-Packages)
Use sub_packages to release several packages under one shared tag,
changelog, and release, while each sub-package still gets its own manifest
updates based on its release_type. A sub-package does not produce its
own tag.
[[package]]
name = "platform"
workspace_root = "."
path = "."
tag_prefix = "v"
sub_packages = [
{ name = "web", path = "packages/web", release_type = "node" },
{ name = "cli", path = "packages/cli", release_type = "rust" },
]
Result: one tag (v1.0.0), one changelog covering everything, one
release — with package.json (web) and Cargo.toml (cli) updated
independently. Reach for this when a group of packages must always ship
together with the same version.
Sub-packages vs. separate packages: separate
[[package]]entries are versioned and tagged independently;sub_packagesshare the parent’s single tag and changelog.
Version Types
By default Releasaurus produces semantic versions (major.minor.patch). Set
version_type to change the version format — globally, or per package
to override the global value.
version_type | Example output |
|---|---|
major.minor.patch (default) | 1.4.0 |
major.minor.patch+timestamp.sha | 1.4.0+1700000000.abc1234 |
year.month.day | 2026.6.14 |
year.month.day+hour.minute.second | 2026.6.14+15.30.45 |
year.month.day+hour.minute.second.micro | 2026.6.14+15.30.45.123456 |
[defaults.versioning]
version_type = "major.minor.patch"
[[package]]
path = "./nightly"
release_type = "node"
versioning = { version_type = "year.month.day+hour.minute.second" }
major.minor.patch— standard semver driven by conventional commits.major.minor.patch+timestamp.sha— semver with build metadata of the form{commit-timestamp}.{short-sha}, for sortable, traceable builds.year.month.dayand the+hour.minute.second[.micro]variants — calendar-based versions derived from the current UTC time; commits and the previous tag are ignored. Plainyear.month.dayallows one release per day by design; a same-day re-run reports nothing to release. Use a time-based variant when you need multiple releases per day.
major.minor.patch and major.minor.patch+timestamp.sha both honor
[prerelease] (below) and the semver increment controls
(breaking_always_increment_major, features_always_increment_minor,
custom_major_increment_regex, custom_minor_increment_regex). For
date-based types those settings are ignored — if you set any of them
explicitly alongside a date-based version_type, Releasaurus logs a warning
naming the package and setting so the no-op config does not pass silently.
Prereleases
Publish alpha/beta/rc/snapshot versions before a stable release. Configure
for every package with [defaults.versioning.prerelease], or per-package
with a versioning.prerelease table. Prereleases apply to the
major.minor.patch and major.minor.patch+timestamp.sha
version types only.
[defaults.versioning.prerelease]
suffix = "alpha"
strategy = "versioned" # or "static"
[[package]]
path = "."
release_type = "node"
Strategies
versioned(default) — appends an incrementing counter:1.1.0-alpha.1,1.1.0-alpha.2, …static— appends the suffix as-is, with no counter:1.0.1-SNAPSHOT(common in Java).
Lifecycle
Change behavior by editing the config and opening a new release PR:
| From | Config change | Result |
|---|---|---|
v1.0.0 | suffix = "alpha" (+ feature commit) | v1.1.0-alpha.1 |
v1.1.0-alpha.1 | unchanged (+ fix commit) | v1.1.0-alpha.2 |
v1.0.0-alpha.3 | suffix = "beta" (+ feature) | v1.1.0-beta.1 |
v1.0.0-alpha.5 | remove the prerelease table (or suffix = "") | v1.0.0 |
Switching the suffix recalculates the base version and resets the counter. Removing the prerelease config graduates to a stable release.
Per-Package Overrides
[defaults.versioning.prerelease]
suffix = "beta"
strategy = "versioned"
[[package]]
path = "./stable"
release_type = "rust"
# inherits the default beta prerelease
[[package]]
path = "./experimental"
release_type = "rust"
versioning = { prerelease = { suffix = "alpha", strategy = "versioned" } }
A package’s prerelease table replaces the [defaults] one rather than
merging with it, so experimental restates strategy even though it
matches the default value. Omit it and that package falls back to the
versioned built-in — not to your [defaults] setting.
Aggregating Prerelease Notes
When graduating to stable, include the changelog entries from every prior prerelease:
[defaults.changelog]
aggregate_prereleases = true
You can also override prerelease settings per run without editing the
config — see Configuration Overrides
(--prerelease-suffix, --prerelease-strategy, --set-package).
Per-Package Changelog
Changelog settings normally live under [defaults.changelog] (rendering) and
[defaults.versioning] (commit filtering and grouping) and apply to every
package. A single package can override either on its own changelog or
versioning key. Since packages are an array of tables ([[package]]),
set them as inline tables so they stay scoped to that entry:
[defaults.changelog]
include_author = true
include_pr_link = true
[defaults.versioning.named_parsers]
ci.skip = true
[[package]]
name = "frontend"
path = "./apps/web"
release_type = "node"
changelog = { include_author = false }
versioning = { named_parsers = { ci = { skip = false } } }
Both merge field-by-field with their
[defaults]counterpart. Any field you set on the package wins; any field you omit is inherited from[defaults](and then the built-in defaults).custom_parserentries from[defaults]and the package are combined, with the package’s checked first, andnamed_parsersoverrides apply per group and per field. See Changelog Customization.
Skipping or Rewording Commits
skip_shas and reword live under [repository]. They operate on the
repository’s shared commit history and affect version calculation as well
as the changelog, so they are repo-wide and cannot be overridden per
package.
skip_shas removes specific commits by SHA prefix (use 7+ characters) —
handy for commits that shouldn’t affect versioning or appear in the
changelog:
[repository]
skip_shas = ["abc123d", "def456e"]
reword rewrites a commit’s message. The new message affects both the
changelog text and the version bump — changing fix: to feat:, for
example, bumps minor instead of patch:
[[repository.reword]]
sha = "abc123d"
message = "feat: added user authentication"
Both have CLI equivalents for one-off runs: --skip-sha <sha> and
--reword <sha>=<message>; a --reword for a SHA already in config wins.
See the Configuration Reference
for the terse lookup form.
skip_shas and reword only affect each package’s next release.
Releasaurus processes a package’s commits from its most recent tag forward,
so once a release is tagged those commits are never reprocessed. (In a
monorepo a single entry can therefore apply to more than one package — but
only that package’s next release in each case.)
If you just want to change how a single release’s notes read — without affecting the version bump — edit them directly in the release PR instead; see Editing Release Notes.
Testing Your Configuration
Validate any config change locally before pushing — no token, no remote changes:
releasaurus release-pr --forge local --repo "."
Check that packages are detected, tag prefixes match, and the combined/separate PR strategy behaves as expected. See Local Repository Mode.
Next Steps
- Changelog Customization — filter commits and customize the template.
- Configuration Reference — every option, default, and the full example config.