A lightning-fast, workflow-first CMake formatter — built in Rust, built to last.

The above demo was generated with VHS.
cmakefmt replaces the aging Python cmake-format tool with a
single native binary. Same spirit. No Python.
- crates.io:
cmakefmt-rust - CLI name:
cmakefmt
[!NOTE]
This project is independent from other Rust implementations, including:
azais-corentin/cmakefmtandyamadapc/cmakefmt.
- Why
cmakefmt? - Performance
- Installation
- Quick Start
- Common Workflows
- Configuration
- Formatter Disable Regions
- Library Usage
- Documentation
- Project Layout
- Development
- Status
- License
Why cmakefmt?
- 104× faster — not a typo. Geometric-mean speedup of
104×overcmake-formaton real-world per-file corpora, rising to 2,853× on whole-repository runs. Pre-commit hooks that once made you wince now finish before you blink. - Zero dependencies. One binary. No Python environment, no virtualenv bootstrap, no dependency drift. Drop it in CI and forget about it.
- Built for actual workflows.
--check,--diff,--staged,--changed,--files-from,--show-config,--explain-config, semantic verification, JSON reporting — all first-class, not scripted workarounds. - Knows your commands. Teach
cmakefmtthe argument structure of your project's custom CMake functions and macros. No more generic token-wrapping for code you wrote. - Errors that actually help. Parse and config failures come with file/line context, source snippets, and reproduction hints — not opaque parser noise.
- Designed for real repositories. Comment preservation, disable-region passthrough, config discovery, ignore files, Git-aware file selection, and opt-in parallelism are core features, not afterthoughts.
Performance
| Fixture | Lines | cmakefmt ms |
cmake-format ms |
Speedup |
|---|---|---|---|---|
opencv_flann/CMakeLists.txt |
2 | 6.3 | 55.8 | 8.9× |
googletest/CMakeLists.txt |
36 | 5.4 | 68.2 | 12.6× |
llvm_tablegen/CMakeLists.txt |
83 | 6.4 | 83.8 | 13.1× |
abseil/CMakeLists.txt |
280 | 6.8 | 186.1 | 27.4× |
spdlog/CMakeLists.txt |
413 | 7.7 | 239.1 | 31.1× |
mariadb_server/CMakeLists.txt |
656 | 7.1 | 532.0 | 75.0× |
xnnpack/CMakeLists.txt |
1,354 | 8.6 | 1,568.9 | 182.2× |
opencv/CMakeLists.txt (root) |
2,039 | 9.8 | 43,158.4 | 4,417.2× |
blender/CMakeLists.txt (root) |
2,650 | 8.6 | 2,922.7 | 338.5× |
llvm/libc/.../CMakeLists.txt |
6,688 | 8.9 | 2,473.7 | 279.3× |
grpc/CMakeLists.txt (root) |
54,834 | 39.4 | 84,489.2 | 2,146.2× |
Geometric-mean per-file speedup: 104×.
Whole-repository parallel runs (across 14 large open-source repos including
LLVM, blender, opencv, gRPC, and oomph-lib) average 150× faster than
cmake-format geo-mean (95× serial), with parallel mode delivering
up to 2.9× over cmakefmt serial on large repositories.
Full methodology and profiler notes: cmakefmt.dev/performance/.
Update the pinned local corpus and generate local before/after review artifacts with:
Installation
Homebrew (macOS):
Cargo (any platform):
pip (any platform with Python):
conda-forge:
Pre-built binaries (Linux, macOS, and Windows):
Download the .zip / .tar.gz for your platform from
GitHub Releases,
extract, and place the binary on your PATH.
Build from source:
Verify:
Release channels and support levels are documented at cmakefmt.dev/release/. Shell completion installation instructions are available at cmakefmt.dev/install/.
Quick Start
Common Workflows
| Task | Command |
|---|---|
| Format file to stdout | cmakefmt CMakeLists.txt |
| Rewrite files in place | cmakefmt --in-place . |
| CI check | cmakefmt --check . |
| Preview which files would change | cmakefmt --list-changed-files . |
| See the exact patch | cmakefmt --diff CMakeLists.txt |
| Verify semantics while formatting to stdout | cmakefmt --verify CMakeLists.txt |
| Pre-commit guard (staged files only) | cmakefmt --staged --check |
| PR-scoped check | cmakefmt --changed --since origin/main --check |
| Machine-readable CI output | cmakefmt --check --report-format json . |
| GitHub Actions annotations | cmakefmt --check --report-format github . |
| Checkstyle / JUnit / SARIF output | cmakefmt --check --report-format checkstyle . |
| Pin the required binary version in CI | cmakefmt --required-version 1.2.0 --check . |
| Speed up repeated large-repo checks | cmakefmt --cache --check . |
| Roll out formatting file-by-file | cmakefmt --require-pragma --check . |
| Find project-specific commands | cmakefmt --list-unknown-commands . |
| Watch and auto-format on save | cmakefmt --watch . |
| Explain formatting decisions | cmakefmt --explain CMakeLists.txt |
| Read from stdin | cat CMakeLists.txt | cmakefmt - |
Configuration
cmakefmt searches upward from each file for .cmakefmt.yaml, .cmakefmt.yml, or .cmakefmt.toml.
YAML is recommended for larger configs.
Example .cmakefmt.yaml:
format:
line_width: 100
tab_size: 4
style:
command_case: lower
keyword_case: upper
markup:
enable_markup: true
Debug which config a file is actually using:
Migrate from an existing cmake-format config:
Full config reference: cmakefmt.dev/config/.
Formatter Disable Regions
Selectively opt out of formatting with barrier comments.
There are three barrier styles:
-
Legacy
cmake-formatdirectives:# cmake-format: off set(MESSY_THING a b c) # kept verbatim # cmake-format: on -
Native directive barriers, using either
cmakefmtor the shorterfmtspelling:# cmakefmt: off set(MESSY_THING a b c) # kept verbatim # cmakefmt: on # fmt: off set(MESSY_THING a b c) # kept verbatim # fmt: on -
Fence barriers, which toggle formatting on and off each time
# ~~~appears:# ~~~ set(MESSY_THING a b c) # kept verbatim # ~~~
Use directive barriers when you want an explicit start/end marker, and fence barriers when you want a shorter toggle-style block.
Library Usage
cmakefmt is also available as a Rust library:
use ;
Full API docs: cmakefmt.dev/api/.
Documentation
Start here: https://cmakefmt.dev.
| Doc | Description |
|---|---|
| Install | Install options, first-project setup, CI wiring |
| Coverage | How coverage is measured, published, and interpreted |
| Release Channels | Release contract, support levels, and release artifacts |
| CLI Reference | Every flag, exit code, and discovery rule |
| Config Reference | Full config schema with examples |
| Formatter Behavior | How the formatter makes layout decisions |
Migration from cmake-format |
Incremental rollout guide and CLI mapping |
| Library API | Embedding cmakefmt in your own Rust tools |
| Troubleshooting | Common issues and debug workflow |
| Performance | Benchmark methodology and profiler notes |
| Contributing | How to contribute, run tests, and open PRs |
| Changelog | What's changed in each release |
Preview the full docs locally:
&& &&
Project Layout
cmakefmt/
├── docs/ # Astro + Starlight source published to cmakefmt.dev
├── src/ # CLI, library API, parser, config, spec, formatter
├── tests/ # integration tests, snapshots, and fixtures
├── benches/ # Criterion benchmarks
├── scripts/ # repo maintenance and docs helpers
└── .github/ # CI and Pages workflows
Key modules under src/:
main.rs: CLI entry point and workflow orchestrationlib.rs: public library APIconfig/: config loading, merging, and legacy conversionparser/: hand-written parser, AST, and lowering pipelinespec/: built-in and user-defined command registryformatter/: AST-to-doc formatting logic and comment handlingfiles.rs: file discovery and ignore handling
Development
Install pre-commit hooks:
Status
The repository is stable and actively maintained. cmakefmt is still
pre-1.0, so release packaging, package-manager distribution, and some output
or API details may continue to evolve. The built-in command registry is audited
through CMake 4.3.1.
Hit something unexpected? See Troubleshooting or run:
License
cmakefmt is dual-licensed under MIT or Apache-2.0 at your option.