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 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_layoutwrap_after_first_argcontinuation_alignenable_sortautosortdangle_parensdangle_alignmin_prefix_lengthmax_prefix_lengthspace_before_control_parenspace_before_definition_paren
- Casing 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 wrap_after_first_arg: false enable_sort: false autosort: 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 command_case: lower keyword_case: upper
markup: enable_markup: true 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: trueFormat 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.
wrap_after_first_arg
Section titled “wrap_after_first_arg”When wrapping a command across multiple lines, keep the first positional
argument on the command line and align continuation lines to the open
parenthesis. Default: false.
format: wrap_after_first_arg: trueWhen enabled globally, all commands that wrap will keep their first argument attached:
# wrap_after_first_arg: truetarget_link_libraries(mylib PUBLIC dep1 dep2 PRIVATE dep3 dep4)
# wrap_after_first_arg: false (default)target_link_libraries( mylib PUBLIC dep1 dep2 PRIVATE dep3 dep4)Built-in default for set(): The set command has wrap_after_first_arg
enabled in its built-in spec, so the variable name always stays on the
set( line regardless of the global setting:
# set() always keeps the variable name attachedset(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build mode." FORCE)
set(SOURCES a.cpp b.cpp c.cpp)Override per-command via per_command_overrides:
per_command_overrides: set: wrap_after_first_arg: falseOr enable for a specific custom command in the spec:
commands: my_cmd: pargs: 1 layout: wrap_after_first_arg: true kwargs: SOURCES: nargs: "+"continuation_align
Section titled “continuation_align”How to indent continuation lines when a wrapped keyword section (like a
subkwarg plus its values) overflows line_width. Two modes:
under-first-value(default) — the continuation aligns under the column of the first value after the keyword (the cmake-format hanging-indent style). Keeps continuation visually grouped with the keyword, removing the ambiguity between a continuation and a new sibling subkwarg.same-indent— the continuation wraps at the same indent as the keyword itself. Consistent with how cmakefmt wraps flat-list sections and positional arg lists elsewhere.
format: continuation_align: same-indentThe knob only affects subkwarg groups inside structural kwarg sections
(e.g. PATTERN … PERMISSIONS … inside install(DIRECTORY) or
RUNTIME COMPONENT … inside install(TARGETS)); flat-list sections
like PUBLIC in target_link_libraries are unaffected.
With a long PERMISSIONS value list inside a PATTERN subgroup:
# under-first-value (default) — continuation aligned under OWNER_EXECUTE's columninstall(DIRECTORY src/ DESTINATION include PATTERN *.h PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)
# same-indent — continuation at the subkwarg's own indentinstall(DIRECTORY src/ DESTINATION include PATTERN *.h PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)Override per-command via per_command_overrides:
per_command_overrides: install: continuation_align: same-indentOr in a custom spec via layout.continuation_align.
enable_sort
Section titled “enable_sort”Sort arguments in keyword sections marked sortable in the command spec.
Sorting is lexicographic and case-insensitive. Default: false.
format: enable_sort: trueMark a keyword section as sortable in a custom command spec:
commands: my_cmd: kwargs: SOURCES: nargs: "+" sortable: trueautosort
Section titled “autosort”Heuristically sort keyword sections even without an explicit sortable
annotation. A section is considered sortable if all its arguments are simple
unquoted tokens (no variables, generator expressions, or quoted strings).
Requires enable_sort: true to have any effect. Default: false.
format: enable_sort: true autosort: trueSome keyword sections have positional semantics inside their value list
that flat sorting would silently corrupt — for example, the property name
in set_property(... PROPERTY <name> <values…>), or the <key> <value>
pair structure under PROPERTIES in set_target_properties and the
related set_*_properties commands. The built-in specs for these
commands mark the affected sections with no_autosort: true, so
autosort skips them. An explicit sortable: true on a custom spec
still takes precedence — no_autosort only protects against the
heuristic.
To opt one of your own custom-spec sections out of autosort:
commands: my_cmd: kwargs: PROPERTY: nargs: "+" no_autosort: truedangle_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 ()Casing Options
Section titled “Casing Options”command_case
Section titled “command_case”Controls the casing of command names.
Allowed values:
lowerupperunchanged
format: command_case: lowerkeyword_case
Section titled “keyword_case”Controls the casing of recognized keywords and flags.
Allowed values:
lowerupperunchanged
format: 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 reflows plain line comments to fit within the configured line width and can recognize lists, fences, and rulers inside comments rather than treating them as opaque text.
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.
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.
Related Reading
Section titled “Related Reading”
Docs track main. For historical docs, check out a release tag in
the repository and build
docs/ locally.