Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 configCommit messagePR title
separate_pull_requests = truecommit_message_templatepr_title_template
One [[package]]commit_message_templatepr_title_template
Multiple [[package]] and separate_pull_requests = falsemonorepo_commit_message_templatemonorepo_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 = false uses the monorepo_* 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. Use separate_pull_requests = true if 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:

VariableDescriptionExample
branchThe base branch being released tomain
repo_nameRepository namemy-repo

Available in commit_message_template and pr_title_template only, because a PR spanning several packages has no single one of these:

VariableDescriptionExample
package_nameName of the package being releasedfrontend
tagFull tag, including the tag prefixweb-v1.2.3
semverVersion alone, without the prefix1.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 name field where one exists (package.json, Cargo.toml, etc.).
  • The full path (workspace_root + path) must be unique. Two packages may share a path only if their workspace_root differs.
  • 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_packages share 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_typeExample output
major.minor.patch (default)1.4.0
major.minor.patch+timestamp.sha1.4.0+1700000000.abc1234
year.month.day2026.6.14
year.month.day+hour.minute.second2026.6.14+15.30.45
year.month.day+hour.minute.second.micro2026.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.day and the +hour.minute.second[.micro] variants — calendar-based versions derived from the current UTC time; commits and the previous tag are ignored. Plain year.month.day allows 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:

FromConfig changeResult
v1.0.0suffix = "alpha" (+ feature commit)v1.1.0-alpha.1
v1.1.0-alpha.1unchanged (+ fix commit)v1.1.0-alpha.2
v1.0.0-alpha.3suffix = "beta" (+ feature)v1.1.0-beta.1
v1.0.0-alpha.5remove 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_parser entries from [defaults] and the package are combined, with the package’s checked first, and named_parsers overrides 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