Expand description
§⬆️ Bump2version
bump2versionis the world’s fastest version bumper written entirely in 100% safe Rust, withno_stdsupport, native Python and Node.js bindings, and acargo bumpsubcommand 🗿.
§🚀 Installation
| Platform | Command |
|---|---|
| Rust binary | cargo install bump2version --features rust-binary |
| Cargo subcommand | cargo bump --help |
| Docker | docker pull wiseaidev/bump2version |
| Debian/Ubuntu | Download .deb from GitHub Releases |
| RHEL/Fedora | Download .rpm from GitHub Releases |
| Windows | Download bump.exe from GitHub Releases |
| GitHub Action | See action.yml |
| Python | pip install bump-rs |
| Node.js | npm install bump2version |
[!NOTE] Installing via
cargoinstalls bothbumpandbump2versionbinaries. The originalbump2versionbinary is retained indefinitely for backward compatibility with existing tutorials, CI/CD pipelines, and automation scripts.
§🤔 What does this crate provide?
bump2version automates semantic version management for any project regardless of language. It:
- Parses version strings using a fully configurable regex (default: semver
major.minor.patch). - Bumps any named component (
major,minor,patch, or custom cyclic stages likealpha → beta → rc → stable). - Rewrites version occurrences across multiple files, including multiline CHANGELOG patterns.
- Commits and tags via 100% pure
gix(gitoxide); zero subprocess calls. - Detects version strings across any language’s manifest files (Rust, Python, JS, Go, Java, Ruby).
- Watches for file changes and bumps automatically on save (one bump per save, with debounce).
- Bumps workspaces atomically across all Cargo workspace members.
§💻 Command-line Interface
# Install
cargo install bump2version --features rust-binary
# Use directly
bump --bump patch # 0.2.1 → 0.2.2
bump --bump minor # 0.2.1 → 0.3.0
bump --bump major # 0.2.1 → 1.0.0
bump --bump patch --dry-run # preview only
# Use as cargo subcommand
cargo bump --bump patch
cargo bump --bump minor --dry-run
# Docker
docker run --rm -v $(pwd):/workspace wiseaidev/bump2version --bump patch --dry-run
# Multi-language auto-detect
bump --bump patch --detect| Option | Description |
|---|---|
--config-file | Config file path (default: .bumpversion.toml) |
--current-version | Override current version |
--bump | Component: major, minor, patch, or any custom part |
--parse | Parse regex override |
--serialize | Serialize format override |
--dry-run / -n | Simulate without writing files |
--new-version | Explicit new version (skips bump calculation) |
--commit / --tag | Git commit + lightweight tag |
§🔭 Features
| Feature | Default | Description |
|---|---|---|
std | ✅ | File I/O, git integration, regex stdlib cache |
cli | ❌ | Standalone bump binary via clap |
watch | ❌ | File-system watcher (bump on file save) |
detect | ❌ | Multi-language manifest auto-detection |
python | ❌ | Python extension module via PyO3/maturin |
node | ❌ | Node.js native add-on via napi-rs |
§🦀 Rust
The Rust crate is available on crates.io. For a complete API reference visit RUST.md.
§Quick Start
[dependencies]
bump2version = "0.2.2"use bump2version::{config::BumpConfig, version::{BumpPart, parse_version, bump_version, serialize_version}};
fn main() {
let cfg = BumpConfig::default();
let v = parse_version("1.2.3", &cfg).unwrap();
let v2 = bump_version(&v, &BumpPart::Patch, &cfg).unwrap();
println!("{}", serialize_version(&v2, &cfg)); // 1.2.4
}§no_std Support
Core modules (config, version, files, error) compile in no_std + alloc:
bump2version = { version = "0.2.2", default-features = false }| Module | no_std+alloc | std |
|---|---|---|
config | ✅ | ✅ |
version | ✅ | ✅ |
files | ✅ | ✅ |
error | ✅ | ✅ |
git | ❌ | ✅ |
| CLI | ❌ | ✅ |
| Python / Node.js | ❌ | ✅ |
§🐍 Python
pip install bump-rsfrom bump_rs import bump_version, apply_file_change, BumpConfig
print(bump_version("1.2.3", "patch")) # "1.2.4"
print(bump_version("1.2.3", "minor")) # "1.3.0"
cfg = BumpConfig(parse=r"(?P<major>\d+)\.(?P<minor>\d+)", serialize="{major}.{minor}")
print(bump_version("2.0", "minor", config=cfg)) # "2.1"For full docs see PYTHON.md.
§🟩 Node.js
npm install bump2versionconst { bumpVersion, applyFileChange } = require("bump2version");
console.log(bumpVersion("1.2.3", "patch")); // '1.2.4'For full docs see NODE.md.
§⚙️ Configuration File (.bumpversion.toml)
[bumpversion]
current_version = "1.0.0"
commit = true
tag = true
[bumpversion:file:Cargo.toml]
search = name = "my-crate"
version = "{current_version}"
replace = name = "my-crate"
version = "{new_version}"
[bumpversion:file:CHANGELOG.md]
search = """
## {current_version}
Release notes line 1"""
replace = """
## {new_version}
Release notes line 1"""§Pre-release Cycling
[bumpversion]
current_version = "1.0.0-alpha.1"
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)-(?P<stage>[a-z]+)\.(?P<devnum>\d+)
serialize =
{major}.{minor}.{patch}-{stage}.{devnum}
{major}.{minor}.{patch}
[bumpversion:part:stage]
optional_value = stable
first_value = alpha
values =
alpha
beta
rc
stable§Cargo Workspace Bumping
# Atomically bump all workspace member crates
bump --bump patchThe workspace module discovers all [workspace] members and bumps every Cargo.toml in one pass.
§🔭 GitHub Action
The action is published as bump-rs on the GitHub Marketplace.
- name: bump-rs
uses: wiseaidev/bump2version@v0.2.2
with:
release_type: patch # 'major', 'minor', or 'patch' - omit to auto-detect from git tags
commit: "true"
tag: "true"
dry-run: "false"
working-directory: "."
config-file: ".bumpversion.toml"| Output | Description |
|---|---|
new_version | The new version string after bumping |
old_version | The previous version string before bumping |
release_type | The component that was bumped (major/minor/patch) |
§🔒 Safety
This crate enforces #![forbid(unsafe_code)] at the crate root (except the Node.js FFI layer which requires unsafe for napi-rs interop). Every byte of the implementation: config parsing, regex matching, version bumping, git object creation, is written in safe Rust.
§📊 Benchmarks
§CLI vs CLI: bump vs bump-my-version (hyperfine)
Measured with hyperfine --runs 5 --warmup 2 -N on x86-64 Linux (target-cpu=native release build):
| Scenario | Tool | Mean | Min | Max |
|---|---|---|---|---|
| patch bump | bump (Rust) | 5.6 ms | 2.6 ms | 10.5 ms |
| minor bump | bump (Rust) | 3.9 ms | 2.8 ms | 6.2 ms |
| major bump | bump (Rust) | 2.5 ms | 1.9 ms | 3.2 ms |
| any bump | bump-my-version (Python) | 482.3 ms | 473.8 ms | 488.0 ms |
CLI speedup: ~90-200× faster depending on scenario (major bump is fastest: ~193×).
At the library function level (pure parse+bump+serialize, no process startup):
| Benchmark | Rust (bump2version) | Python (bump-my-version) | Speedup |
|---|---|---|---|
| parse + bump + serialize | ~13 µs | ~79 µs | ~6× |
| Config parse (minimal) | ~12 µs | ~4 800 µs | ~400× |
| File replace, 10K lines | ~14 ms | - | - |
| Full pipeline (CLI cold start) | 2.4 ms | 482 ms | ~200× |
Run the comparison yourself:
# Rust
hyperfine --runs 10 -N "bump --config-file .bumpversion.toml --bump patch --dry-run"
# Python (if installed)
hyperfine --runs 10 "bump-my-version bump patch --dry-run"
# Full comparative suite
chmod +x benchmarks/hyperfine/run_comparison.sh
./benchmarks/hyperfine/run_comparison.sh§Internal Benchmarks (cargo bench)
Run with cargo bench. Results on x86-64 Linux after optimization (LTO=fat, opt-level=3, target-cpu=native):
| Benchmark | Time |
|---|---|
config_parse/minimal | ~12 µs |
config_parse/full_with_parts | ~18 µs |
version_parse/1.0.0 | ~430 ns |
version_bump/patch | ~13 µs |
version_bump/minor | ~14 µs |
version_bump/major | ~6 µs |
prerelease_bump/stage | ~15 µs |
file_replace/100 lines | ~240 µs |
file_replace/1 000 lines | ~1.3 ms |
file_replace/10 000 lines | ~14 ms |
file_replace/100 000 lines | ~140 ms |
worst_case/10 000 lines | ~14 ms |
multiline_replace/100x | ~85 µs |
§📚 Further Reading
- CLI.md: Full CLI command dictionary
- RUST.md: Rust API guide
- PYTHON.md: Python bindings guide
- NODE.md: Node.js bindings guide
- DOCKER.md: Docker usage guide
- WASM.md: WebAssembly + Yew guide
- PACKAGING.md: Debian/RPM packaging
- examples/yew-app: Browser-side version bumper (Yew + WASM)
- Semantic Versioning 2.0.0
- bump-my-version: the Python tool this crate is feature-parity with
- gitoxide (gix): the pure-Rust git implementation
§📄 License
Licensed under the MIT License.
§bump2version Rust Documentation 🦀
The bump2version Rust crate provides a fully thread-safe, library-quality
version bumper. All logic is available both as a CLI binary and as a library
importable in other Rust projects.
§📦 Installation (CLI)
cargo install bump2version --features rust-binaryNote: This installs
bump,cargo-bump, and the originalbump2versionexecutable. The latter is retained for backward compatibility with older tutorials.
§📦 Library Usage
[dependencies]
bump2version = { version = "0.2.2", default-features = false }§🛠 Usage Overview
§Parse a version
use bump2version::config::BumpConfig;
use bump2version::version::parse_version;
let cfg = BumpConfig::default();
let v = parse_version("1.2.3", &cfg).unwrap();
assert_eq!(v["major"].value, "1");
assert_eq!(v["patch"].value, "3");§Bump a version
use bump2version::config::BumpConfig;
use bump2version::version::{BumpPart, bump_version, serialize_version, parse_version};
let cfg = BumpConfig::default();
let v = parse_version("1.2.3", &cfg).unwrap();
let bumped = bump_version(&v, &BumpPart::Minor, &cfg).unwrap();
assert_eq!(serialize_version(&bumped, &cfg), "1.3.0");§Parse config file
use bump2version::config::parse_config_file;
let cfg = parse_config_file(".bumpversion.toml").unwrap();
println!("{:?}", cfg.current_version);§Apply file search/replace
use bump2version::config::{BumpConfig, FileConfig};
use bump2version::files::apply_file_change;
let cfg = BumpConfig::default();
let mut fc = FileConfig::new("Cargo.toml");
fc.search = Some(r#"name = "bump2version"\nversion = "{current_version}""#.to_string());
fc.replace = Some(r#"name = "bump2version"\nversion = "{new_version}""#.to_string());
let content = r#"name = "bump2version"\nversion = "1.0.0""#.to_string();
let updated = apply_file_change(&content, &fc, &cfg, "1.0.0", "1.0.1").unwrap();
assert!(updated.contains("1.0.1"));§Read git author from local config
use bump2version::git::get_git_author;
use gix::open;
let repo = open(".").unwrap();
let (name, email) = get_git_author(&repo).unwrap();
println!("{name} <{email}>");§Installation check
bump --version
# bump 0.2.1
bump2version --version
# bump2version 0.2.1 (backward-compatible alias)
cargo bump --help
# bump 0.2.1 : high-performance version bumper§1. Patch / Minor / Major bump
bump --bump patch # 0.2.1 → 0.2.2
bump --bump minor # 0.2.1 → 0.3.0
bump --bump major # 0.2.1 → 1.0.0§2. Dry-run preview (no files written)
bump --bump patch --dry-run
bump --bump minor -n
# Output: [dry-run] Would commit 1 file(s) with message: Bump version: 0.2.1 → 0.2.2§3. Explicit new version (skip bump calculation)
bump --new-version 2.0.0
bump --new-version 1.0.0-beta.1§4. Override current version
bump --current-version 1.0.0 --bump patch§5. Custom config file
bump --config-file path/to/.bumpversion.toml --bump patch
bump --config-file examples/python/.bumpversion.toml --bump minor --dry-run§6. Git commit
bump --bump patch --commit§7. Git commit + tag
bump --bump patch --commit --tag§8. Custom commit message
bump --bump patch --commit --message "chore: release {new_version}"§9. Extra files on the command line
bump --bump patch README.md CHANGELOG.md
bump --bump patch --dry-run src/main.rs§10. Custom parse regex
bump --bump patch \
--parse '(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)'§11. Custom serialize format
bump --bump patch --serialize '{major}.{minor}.{patch}-dev'§12. Combined: custom parse + serialize + dry-run
bump \
--current-version "1.0.0-alpha.1" \
--parse '(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)-(?P<stage>[a-z]+)\.(?P<devnum>\d+)' \
--serialize '{major}.{minor}.{patch}-{stage}.{devnum}' \
--bump devnum \
--dry-run
# [dry-run] Would bump 1.0.0-alpha.1 → 1.0.0-alpha.2§13. Cargo subcommand
cargo bump --bump patch
cargo bump --bump minor --dry-run
cargo bump --new-version 2.0.0 --commit --tag§14. Docker
docker run --rm -v "$(pwd):/workspace" wiseaidev/bump2version \
--config-file /workspace/.bumpversion.toml \
--bump patch \
--dry-run§15. Watch mode (requires watch feature)
# Monitors .bumpversion.toml and registered files; auto-bumps on save
bump --watch --bump patch§16. Multi-language auto-detect (requires detect feature)
# Scans the directory tree for Cargo.toml, pyproject.toml, package.json, etc.
bump --bump patch --detect
bump --bump minor --detect --dry-run§17. Backward-compatible bump2version binary
# All commands work identically on the bump2version alias:
bump2version --bump patch --dry-run
bump2version --bump minor
bump2version --new-version 2.0.0 --commit --tag§🗂 Examples
All examples live under examples/ with pre-built .bumpversion.toml configs:
| Directory | Language | Key Files |
|---|---|---|
examples/rust-lib | Rust | Cargo.toml |
examples/python | Python | pyproject.toml, setup.cfg |
examples/nodejs | Node.js | package.json |
examples/go | Go | VERSION, main.go |
examples/java | Java (Maven) | pom.xml |
examples/ruby | Ruby | .gemspec, Gemfile |
examples/multi-lang | All 6 at once | all of the above |
examples/yew-app | Yew WASM | browser UI |
§Running any example
# From the project root:
bump --config-file examples/python/.bumpversion.toml --bump patch --dry-run
# From inside the example directory:
cd examples/nodejs
bump --bump minor --dry-run§Detect mode across the multi-lang workspace
cd examples/multi-lang
bump --current-version 0.1.0 --bump patch --detect --dry-run
# [dry-run] Would update: Cargo.toml, pyproject.toml, package.json, VERSION, pom.xml, my-gem.gemspec§📖 Module Overview
| Module | Description |
|---|---|
config | Parse .bumpversion.toml into BumpConfig, FileConfig, PartConfig |
version | Parse version strings, bump components, serialize back to string |
files | Apply single/multiline search-replace with {current_version} tokens |
git | Thread-safe git commit + tag via gix; reads author from git config |
error | Typed BumpError enum |
utils | Higher-level helpers: load_config, compute_new_version, collect_file_configs |
workspace | Atomic workspace-aware bumping across all Cargo workspace members |
detect | Multi-language manifest scanner (requires detect feature) |
watch | File-system watcher loop for auto-bumping (requires watch feature) |
cli | clap-based CLI argument struct (requires cli feature) |
python | PyO3 bindings (requires python feature) |
node | napi-rs bindings (requires node feature) |
§🔗 See Also
§WebAssembly (WASM) Support 🌐
The bump2version core modules (config, version, files, error) natively compile to wasm32-unknown-unknown, no filesystem, no OS threads, no unsafe code. This makes them an excellent drop-in for browser-side version management tools, editor extensions, and Rust frontend apps.
§Framework Compatibility
Because the core logic has zero OS dependencies, bump2version works out-of-the-box with all major Rust frontend frameworks:
§📦 Usage
Add bump2version with no_std (no std feature) to your WASM project’s Cargo.toml:
[dependencies]
bump2version = { version = "0.2.2", default-features = false }§Minimal Example (Yew)
The following component lets the user enter a version string and instantly see the bumped result, entirely in the browser with zero network requests:
use bump2version::config::BumpConfig;
use bump2version::version::{BumpPart, bump_version, parse_version, serialize_version};
use yew::prelude::*;
#[function_component(VersionBumper)]
pub fn version_bumper() -> Html {
let version = use_state(|| "1.2.3".to_string());
let result = use_state(|| "-".to_string());
let on_bump = {
let version = version.clone();
let result = result.clone();
Callback::from(move |part: &'static str| {
let cfg = BumpConfig::default();
if let Ok(parsed) = parse_version(&*version, &cfg) {
if let Ok(bumped) = bump_version(&parsed, &BumpPart::from(part), &cfg) {
result.set(serialize_version(&bumped, &cfg));
}
}
})
};
html! {
<div class="bumper">
<input
value={(*version).clone()}
oninput={Callback::from({
let version = version.clone();
move |e: InputEvent| {
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
version.set(input.value());
}
})}
placeholder="e.g. 1.2.3"
/>
<button onclick={on_bump.reform(|_| "patch")}>{ "Bump Patch" }</button>
<button onclick={on_bump.reform(|_| "minor")}>{ "Bump Minor" }</button>
<button onclick={on_bump.reform(|_| "major")}>{ "Bump Major" }</button>
<p>{ format!("New version: {}", *result) }</p>
</div>
}
}
#[function_component(App)]
pub fn app() -> Html {
html! { <VersionBumper /> }
}
// fn main() {
// yew::Renderer::<App>::new().render();
// }§Full Yew App Example
A reference implementation of a version-bump UI tool built with Yew and bump2version is available in examples/yew-app. It includes:
- Input field for the current version
- Patch / Minor / Major bump buttons
- Pre-release cycling (
alpha → beta → rc → stable) via customBumpConfig - Live output of the new version string
§Running the Example
cd examples/yew-app
cargo install trunk
trunk serve --port 3000
# Open http://localhost:3000 in your browser§Limitations
The WASM build excludes:
| Module | Available in WASM? | Reason |
|---|---|---|
config | ✅ | no_std + alloc |
version | ✅ | no_std + alloc |
files | ✅ | no_std + alloc |
error | ✅ | no_std + alloc |
git | ❌ | requires std::fs and OS APIs |
watch | ❌ | requires OS file-system events |
detect | ❌ | requires walkdir + filesystem |
| CLI | ❌ | requires std::env |
§Example: Building a Version Management Tool
You can use bump2version as the versioning backend for a browser-based release management dashboard. A reference Yew application is in examples/yew-app demonstrating full pre-release lifecycle management in the browser.
Modules§
- cli
cliandstd - CLI Argument Definitions
- config
- Configuration Parsing
- detect
clianddetectandstd - Multi-Language Version Auto-Detection
- error
- Error Types
- files
- File Search and Replace
- git
git - Git Integration
- node
nodeandstd - Node.js Bindings
- utils
std - Utility Helpers
- version
- Version Parsing and Bumping
- watch
cliandstdandwatch - Watch Mode
- workspace
std - Workspace-Aware Bumping

