Config Reference
Everything you need to know to tune cmakefmt for your project.
The short version:
- configuration files may be YAML or TOML
- YAML is the recommended default for hand-edited configs
- custom command syntax goes under
commands: - command-specific layout and style tweaks go under
per_command_overrides:
Config Discovery Order
Section titled “Config Discovery Order”For a given target file, cmakefmt resolves config by layering sources in this
order — higher layers win over lower ones:
- CLI flag overrides (
--line-width,--tab-size,--command-case, etc.) — always win, regardless of what any config file says - Explicit
--config-file <PATH>files, if provided — later files override earlier ones - The nearest
.cmakefmt.yaml,.cmakefmt.yml, or.cmakefmt.tomlfound by walking upward from the target file ~/.cmakefmt.yaml,~/.cmakefmt.yml, or~/.cmakefmt.toml— home-directory fallback- Built-in defaults
If multiple supported config filenames exist in the same directory, YAML is preferred over TOML.
When you want to see exactly what happened:
cmakefmt config path src/CMakeLists.txtcmakefmt config show src/CMakeLists.txtcmakefmt config explainRecommended Starter File
Section titled “Recommended Starter File”YAML is the recommended user-facing format:
format: line_width: 80 tab_size: 2
style: command_case: lower keyword_case: upperGenerate the full starter template with:
cmakefmt config dump > .cmakefmt.yamlIf you prefer TOML:
cmakefmt config dump --format toml > .cmakefmt.tomlTable Of Contents
Section titled “Table Of Contents”- Config Discovery Order
- Recommended Starter File
- Table Of Contents
- Defaults
- Format Options
disableline_endingline_widthtab_sizeuse_tabsfractional_tab_policymax_empty_linesmax_hanging_wrap_linesmax_hanging_wrap_positional_argsmax_hanging_wrap_groupsmax_rows_cmdlinealways_wraprequire_valid_layoutdangle_parensdangle_alignmin_prefix_lengthmax_prefix_lengthspace_before_control_parenspace_before_definition_paren
- Style Options
- Markup Options
commands:vsper_command_overrides:— Which One Do I Need?- Per-command Overrides
- Custom Command Specs
- Old Draft Key Names
- Related Reading
Defaults
Section titled “Defaults”format: disable: false line_ending: unix line_width: 80 tab_size: 2 use_tabs: false fractional_tab_policy: use-space max_empty_lines: 1 max_hanging_wrap_lines: 2 max_hanging_wrap_positional_args: 6 max_hanging_wrap_groups: 2 max_rows_cmdline: 2 always_wrap: [] require_valid_layout: false dangle_parens: false dangle_align: prefix min_prefix_length: 4 max_prefix_length: 10 space_before_control_paren: false space_before_definition_paren: false
style: command_case: lower keyword_case: upper
markup: enable_markup: true reflow_comments: false first_comment_is_literal: true literal_comment_pattern: "" bullet_char: "*" enum_char: "." fence_pattern: "^\\s*[`~]{3}[^`\\n]*$" ruler_pattern: "^[^\\w\\s]{3}.*[^\\w\\s]{3}$" hashruler_min_length: 10 canonicalize_hashrulers: true explicit_trailing_pattern: "#<"Format Options
Section titled “Format Options”disable
Section titled “disable”Disable formatting entirely. When true, cmakefmt returns the source
unchanged — no layout changes, no casing normalization, nothing.
format: disable: trueUseful as a temporary escape hatch or for opting individual files out via a project-local config.
line_ending
Section titled “line_ending”Output line-ending style.
Allowed values:
unix— LF (\n). The default.windows— CRLF (\r\n).auto— detect from the input source; if the input contains any\r\n, use CRLF; otherwise use LF.
format: line_ending: windowsThe formatter normalizes line endings internally to LF. This option controls only the final output.
line_width
Section titled “line_width”Target maximum output width before wrapping is attempted.
format: line_width: 100Raise this if your project prefers wider CMake calls.
tab_size
Section titled “tab_size”Indent width in spaces when use_tabs is false.
format: tab_size: 4use_tabs
Section titled “use_tabs”Use tab characters for indentation instead of spaces.
format: use_tabs: trueThis affects leading indentation only. Internal alignment rules use the configured indentation unit but are not otherwise changed.
fractional_tab_policy
Section titled “fractional_tab_policy”Controls what happens to fractional (sub-tab-stop) indentation when
use_tabs is true.
Allowed values:
use-space— leave remaining spaces as-is (utf-8 0x20). The default.round-up— promote the remaining spaces to a full tab character (utf-8 0x09), shifting the column to the next tab stop.
format: fractional_tab_policy: round-upOnly relevant when use_tabs: true. Has no effect when use_tabs: false.
max_empty_lines
Section titled “max_empty_lines”Maximum number of consecutive blank lines to preserve.
format: max_empty_lines: 1Blank-line runs that exceed this limit are reduced to the configured maximum. Intentional vertical separation is preserved; excessive gaps are removed.
max_hanging_wrap_lines
Section titled “max_hanging_wrap_lines”Maximum number of lines a hanging-wrap layout may consume before the formatter falls back to a more vertical layout.
format: max_hanging_wrap_lines: 2Lower values cause more commands to fall back to fully vertical layout.
max_hanging_wrap_positional_args
Section titled “max_hanging_wrap_positional_args”Maximum positional arguments to keep in a hanging-wrap layout before falling back to a more vertical layout.
format: max_hanging_wrap_positional_args: 6Most noticeable on commands with long source or header lists.
max_hanging_wrap_groups
Section titled “max_hanging_wrap_groups”Maximum number of keyword/flag subgroups to keep in a hanging-wrap layout.
format: max_hanging_wrap_groups: 2Lower this to format keyword-heavy commands with vertical layout more readily.
max_rows_cmdline
Section titled “max_rows_cmdline”Maximum number of rows a hanging-wrap positional group may consume before the formatter rejects the hanging layout and forces nesting.
format: max_rows_cmdline: 2This is a second threshold that works alongside max_hanging_wrap_lines.
Where max_hanging_wrap_lines limits the total line count packed by the token
packer, max_rows_cmdline limits how many rows the result may span before
being rejected outright.
always_wrap
Section titled “always_wrap”A list of command names that the formatter must always lay out vertically, regardless of line width or argument count.
format: always_wrap: - target_link_libraries - target_sourcesCommands in this list skip the inline and hanging-wrap layout attempts and go
directly to vertical layout. This is also configurable per-command via
layout.always_wrap in a custom command spec under commands:.
require_valid_layout
Section titled “require_valid_layout”When true, return an error if any formatted output line exceeds line_width.
The formatter does not guarantee that every line fits — long unbreakable tokens
or deeply nested commands can exceed the limit — and this option makes such
cases visible.
format: require_valid_layout: trueUseful in CI to enforce a strict line-width contract. The error message includes the line number, actual width, and configured limit.
dangle_parens
Section titled “dangle_parens”Place the closing ) on its own line when a call wraps.
format: dangle_parens: trueEffect:
target_link_libraries( foo PUBLIC bar baz)dangle_align
Section titled “dangle_align”Alignment strategy for a dangling closing ).
Allowed values:
prefixopenclose
format: dangle_align: prefixmin_prefix_length
Section titled “min_prefix_length”Lower heuristic bound used when deciding between compact and wrapped layouts.
format: min_prefix_length: 4Leave this alone unless you are deliberately tuning layout behavior.
max_prefix_length
Section titled “max_prefix_length”Upper heuristic bound used when deciding between compact and wrapped layouts.
format: max_prefix_length: 10Like min_prefix_length, this is primarily for advanced layout tuning and rarely needs adjustment.
space_before_control_paren
Section titled “space_before_control_paren”Insert a space before ( for control-flow commands such as if, foreach,
and while.
format: space_before_control_paren: trueEffect:
if (WIN32) message(STATUS "Windows")endif ()space_before_definition_paren
Section titled “space_before_definition_paren”Insert a space before ( for function and macro definitions.
format: space_before_definition_paren: trueEffect:
function (my_helper arg) ...endfunction ()Style Options
Section titled “Style Options”command_case
Section titled “command_case”Controls the casing of command names.
Allowed values:
lowerupperunchanged
style: command_case: lowerkeyword_case
Section titled “keyword_case”Controls the casing of recognized keywords and flags.
Allowed values:
lowerupperunchanged
style: keyword_case: upperExample — with command_case: lower and keyword_case: upper:
target_link_libraries(foo PUBLIC bar)stays:
target_link_libraries(foo PUBLIC bar)With command_case: upper and keyword_case: lower:
TARGET_LINK_LIBRARIES(foo public bar)Markup Options
Section titled “Markup Options”enable_markup
Section titled “enable_markup”Enable comment-markup awareness.
markup: enable_markup: trueWhen enabled, the formatter can recognize lists, fences, and rulers inside comments rather than treating them as opaque text.
reflow_comments
Section titled “reflow_comments”Reflow plain line comments to fit within the configured line width.
markup: reflow_comments: trueLeave this false if you want comments preserved more literally.
first_comment_is_literal
Section titled “first_comment_is_literal”Preserve the first comment block in a file without any reflowing or markup processing.
markup: first_comment_is_literal: trueUseful for license headers or hand-crafted introductory comments that must stay exactly as written.
literal_comment_pattern
Section titled “literal_comment_pattern”Regex for comments that should never be reflowed.
markup: literal_comment_pattern: "^\\s*NOTE:"Use this for project-specific comment conventions that must stay untouched.
bullet_char
Section titled “bullet_char”Preferred bullet character when normalizing markup lists.
markup: bullet_char: "*"enum_char
Section titled “enum_char”Preferred punctuation for numbered lists when normalizing markup.
markup: enum_char: "."fence_pattern
Section titled “fence_pattern”Regex describing fenced literal comment blocks.
markup: fence_pattern: "^\\s*[`~]{3}[^`\\n]*$"Keep the default unless your project has a strong house style.
ruler_pattern
Section titled “ruler_pattern”Regex describing ruler-style comments that should be treated specially.
markup: ruler_pattern: "^[^\\w\\s]{3}.*[^\\w\\s]{3}$"hashruler_min_length
Section titled “hashruler_min_length”Minimum length before a hash-only line is treated as a ruler.
markup: hashruler_min_length: 10canonicalize_hashrulers
Section titled “canonicalize_hashrulers”Normalize hash-ruler comments when markup handling is enabled.
markup: canonicalize_hashrulers: trueIf your project uses decorative comment rulers and wants them normalized consistently, keep this enabled.
explicit_trailing_pattern
Section titled “explicit_trailing_pattern”A regex pattern that identifies inline comments as explicitly trailing their preceding argument. When a comment matches this pattern it is rendered on the same line as the preceding token rather than on its own indented line.
markup: explicit_trailing_pattern: "#<"The default #< means that inline comments starting with #< are treated as
trailing the immediately preceding argument.
Example — given explicit_trailing_pattern: "#<":
target_sources( mylib PRIVATE src/foo.cpp #< main module src/bar.cpp #< helper)Without this option the #< comments would each appear on their own line.
Set to an empty string to disable explicit trailing comment detection entirely.
commands: vs per_command_overrides: — Which One Do I Need?
Section titled “commands: vs per_command_overrides: — Which One Do I Need?”These two config sections are easy to confuse. The short rule:
| Question | Answer |
|---|---|
”The formatter doesn’t know what SOURCES or QUIET mean in my command.” | Use commands: — teach it the argument structure. |
| ”The formatter knows the command fine, but I want it wider / different casing.” | Use per_command_overrides: — change the layout knobs only. |
In other words: commands: is about what the arguments mean; per_command_overrides: is about how they get laid out on the page.
Per-command Overrides
Section titled “Per-command Overrides”Use per_command_overrides: to change formatting knobs for one command name
without touching that command’s argument syntax.
Example:
per_command_overrides: my_custom_command: line_width: 120 command_case: unchanged keyword_case: upper tab_size: 4 dangle_parens: false dangle_align: prefix max_hanging_wrap_positional_args: 8 max_hanging_wrap_groups: 3Supported override fields:
command_casekeyword_caseline_widthtab_sizedangle_parensdangle_alignmax_hanging_wrap_positional_argsmax_hanging_wrap_groups
Use this when you want a command to format differently from the global defaults.
Do not use it to define a command’s argument structure — that belongs in
commands:.
Custom Command Specs
Section titled “Custom Command Specs”Use commands: to teach cmakefmt about custom functions and macros, or to
override the built-in shape of an existing command.
Without a spec, cmakefmt sees every token as an undifferentiated positional
argument and has no way to group keyword sections or recognize flags. With a
spec, it understands the structure and can produce properly grouped, readable
output.
Before and after
Section titled “Before and after”Consider this call — long enough to exceed the default line_width of 80:
my_library(mylib SOURCES src/foo.cpp src/bar.cpp src/baz.cpp LIBRARIES Boost::filesystem fmt::fmt spdlog::spdlog QUIET)Without a spec, cmakefmt has no idea that SOURCES and LIBRARIES are
keywords or that QUIET is a flag. It treats every token as a positional
argument and wraps them all at the same indent level, with no grouping:
my_library( mylib SOURCES src/foo.cpp src/bar.cpp src/baz.cpp LIBRARIES Boost::filesystem fmt::fmt spdlog::spdlog QUIET)After adding this spec:
commands: my_library: pargs: 1 flags: - QUIET kwargs: SOURCES: nargs: "+" LIBRARIES: nargs: "+"With a spec, cmakefmt groups each keyword with its values in a
hanging-wrap layout, and recognizes QUIET as a standalone flag:
my_library( mylib SOURCES src/foo.cpp src/bar.cpp src/baz.cpp LIBRARIES Boost::filesystem fmt::fmt spdlog::spdlog QUIET)Spec fields
Section titled “Spec fields”How many positional arguments appear before keyword/flag processing begins.
Accepts an integer or one of the nargs strings described below.
commands: my_command: pargs: 2 # exactly two positional args before keywordsA list of standalone keyword tokens that take no values. When cmakefmt sees
one of these tokens it treats it as a boolean flag, not the start of a keyword
section.
commands: my_command: flags: - QUIET - REQUIRED - GLOBALkwargs
Section titled “kwargs”Keyword sections that accept one or more values. Each entry names the keyword
and specifies how many values follow it via nargs.
commands: my_command: kwargs: OUTPUT_DIRECTORY: nargs: 1 # exactly one value SOURCES: nargs: "+" # one or more values OPTIONAL_SOURCES: nargs: "*" # zero or more values MAYBE_ONE: nargs: "?" # zero or one value AT_LEAST_TWO: nargs: "2+" # two or more valuesnargs values:
| Value | Meaning |
|---|---|
1, 2, … | Exactly that many values |
"*" | Zero or more values |
"+" | One or more values |
"?" | Zero or one value |
"N+" e.g. "2+" | At least N values |
Keywords can also nest their own flags and kwargs for commands with
multi-level structure:
commands: my_command: kwargs: INSTALL: nargs: 0 kwargs: DESTINATION: nargs: 1 flags: - OPTIONALlayout
Section titled “layout”Per-command layout hints that override the global config for this command only.
commands: my_command: pargs: 1 kwargs: SOURCES: nargs: "+" layout: always_wrap: true # always use vertical layout line_width: 120 # allow wider lines for this command tab_size: 4 dangle_parens: trueDiscriminated commands
Section titled “Discriminated commands”Some commands dispatch on their first token — file(), install(), and
string() are typical examples. You can define a separate form for each
discriminator and an optional fallback:
commands: my_command: forms: READ: pargs: 1 kwargs: INTO: nargs: 1 WRITE: pargs: 1 kwargs: CONTENT: nargs: 1 fallback: pargs: "*"cmakefmt picks the form whose key matches the first argument
(case-insensitively) and falls back to fallback when nothing matches.
A larger example
Section titled “A larger example”commands: my_library: pargs: 1 flags: - QUIET - EXCLUDE_FROM_ALL kwargs: SOURCES: nargs: "+" HEADERS: nargs: "*" LIBRARIES: nargs: "+" INSTALL: nargs: 0 kwargs: DESTINATION: nargs: 1 flags: - OPTIONAL layout: always_wrap: trueWith this spec, given:
my_library(mylib SOURCES src/foo.cpp src/bar.cpp src/baz.cpp HEADERS include/foo.h include/bar.h LIBRARIES Boost::filesystem fmt::fmt INSTALL DESTINATION lib/mylib OPTIONAL QUIET)cmakefmt produces:
my_library( mylib SOURCES src/foo.cpp src/bar.cpp src/baz.cpp HEADERS include/foo.h include/bar.h LIBRARIES Boost::filesystem fmt::fmt INSTALL DESTINATION lib/mylib OPTIONAL QUIET)always_wrap: true in the layout forces the vertical layout unconditionally.
Each keyword group starts on its own line. Without this flag, short calls that
fit within line_width would stay on a single line.
For larger custom specs, YAML requires less punctuation and is easier to read with deeply nested structures, which is why the default starter config is YAML.
Old Draft Key Names
Section titled “Old Draft Key Names”The current cmakefmt config schema only accepts the clearer names on this
page. If you have an older local config, rename any of the following before use:
| Old key | New key |
|---|---|
use_tabchars | use_tabs |
max_pargs_hwrap | max_hanging_wrap_positional_args |
max_subgroups_hwrap | max_hanging_wrap_groups |
separate_ctrl_name_with_space | space_before_control_paren |
separate_fn_name_with_space | space_before_definition_paren |
cmakefmt fails fast on unknown config keys rather than silently ignoring them
— so you will know immediately if any remain.