Skip to content

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:

For a given target file, cmakefmt resolves config by layering sources in this order — higher layers win over lower ones:

  1. CLI flag overrides (--line-width, --tab-size, --command-case, etc.) — always win, regardless of what any config file says
  2. Explicit --config-file <PATH> files, if provided — later files override earlier ones
  3. The nearest .cmakefmt.yaml, .cmakefmt.yml, or .cmakefmt.toml found by walking upward from the target file
  4. ~/.cmakefmt.yaml, ~/.cmakefmt.yml, or ~/.cmakefmt.toml — home-directory fallback
  5. 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:

Terminal window
cmakefmt config path src/CMakeLists.txt
cmakefmt config show src/CMakeLists.txt
cmakefmt config explain

YAML is the recommended user-facing format:

format:
line_width: 80
tab_size: 2
style:
command_case: lower
keyword_case: upper

Generate the full starter template with:

Terminal window
cmakefmt config dump > .cmakefmt.yaml

If you prefer TOML:

Terminal window
cmakefmt config dump --format toml > .cmakefmt.toml
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: "#<"

Disable formatting entirely. When true, cmakefmt returns the source unchanged — no layout changes, no casing normalization, nothing.

format:
disable: true

Useful as a temporary escape hatch or for opting individual files out via a project-local config.

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: windows

The formatter normalizes line endings internally to LF. This option controls only the final output.

Target maximum output width before wrapping is attempted.

format:
line_width: 100

Raise this if your project prefers wider CMake calls.

Indent width in spaces when use_tabs is false.

format:
tab_size: 4

Use tab characters for indentation instead of spaces.

format:
use_tabs: true

This affects leading indentation only. Internal alignment rules use the configured indentation unit but are not otherwise changed.

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-up

Only relevant when use_tabs: true. Has no effect when use_tabs: false.

Maximum number of consecutive blank lines to preserve.

format:
max_empty_lines: 1

Blank-line runs that exceed this limit are reduced to the configured maximum. Intentional vertical separation is preserved; excessive gaps are removed.

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: 2

Lower values cause more commands to fall back to fully vertical layout.

Maximum positional arguments to keep in a hanging-wrap layout before falling back to a more vertical layout.

format:
max_hanging_wrap_positional_args: 6

Most noticeable on commands with long source or header lists.

Maximum number of keyword/flag subgroups to keep in a hanging-wrap layout.

format:
max_hanging_wrap_groups: 2

Lower this to format keyword-heavy commands with vertical layout more readily.

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: 2

This 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.

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_sources

Commands 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:.

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: true

Useful in CI to enforce a strict line-width contract. The error message includes the line number, actual width, and configured limit.

Place the closing ) on its own line when a call wraps.

format:
dangle_parens: true

Effect:

target_link_libraries(
foo
PUBLIC
bar
baz
)

Alignment strategy for a dangling closing ).

Allowed values:

  • prefix
  • open
  • close
format:
dangle_align: prefix

Lower heuristic bound used when deciding between compact and wrapped layouts.

format:
min_prefix_length: 4

Leave this alone unless you are deliberately tuning layout behavior.

Upper heuristic bound used when deciding between compact and wrapped layouts.

format:
max_prefix_length: 10

Like min_prefix_length, this is primarily for advanced layout tuning and rarely needs adjustment.

Insert a space before ( for control-flow commands such as if, foreach, and while.

format:
space_before_control_paren: true

Effect:

if (WIN32)
message(STATUS "Windows")
endif ()

Insert a space before ( for function and macro definitions.

format:
space_before_definition_paren: true

Effect:

function (my_helper arg)
...
endfunction ()

Controls the casing of command names.

Allowed values:

  • lower
  • upper
  • unchanged
style:
command_case: lower

Controls the casing of recognized keywords and flags.

Allowed values:

  • lower
  • upper
  • unchanged
style:
keyword_case: upper

Example — 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)

Enable comment-markup awareness.

markup:
enable_markup: true

When enabled, the formatter can recognize lists, fences, and rulers inside comments rather than treating them as opaque text.

Reflow plain line comments to fit within the configured line width.

markup:
reflow_comments: true

Leave this false if you want comments preserved more literally.

Preserve the first comment block in a file without any reflowing or markup processing.

markup:
first_comment_is_literal: true

Useful for license headers or hand-crafted introductory comments that must stay exactly as written.

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.

Preferred bullet character when normalizing markup lists.

markup:
bullet_char: "*"

Preferred punctuation for numbered lists when normalizing markup.

markup:
enum_char: "."

Regex describing fenced literal comment blocks.

markup:
fence_pattern: "^\\s*[`~]{3}[^`\\n]*$"

Keep the default unless your project has a strong house style.

Regex describing ruler-style comments that should be treated specially.

markup:
ruler_pattern: "^[^\\w\\s]{3}.*[^\\w\\s]{3}$"

Minimum length before a hash-only line is treated as a ruler.

markup:
hashruler_min_length: 10

Normalize hash-ruler comments when markup handling is enabled.

markup:
canonicalize_hashrulers: true

If your project uses decorative comment rulers and wants them normalized consistently, keep this enabled.

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:

QuestionAnswer
”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.

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: 3

Supported override fields:

  • command_case
  • keyword_case
  • line_width
  • tab_size
  • dangle_parens
  • dangle_align
  • max_hanging_wrap_positional_args
  • max_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:.

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.

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)

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 keywords

A 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
- GLOBAL

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 values

nargs values:

ValueMeaning
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:
- OPTIONAL

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: true

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.

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: true

With 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.

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 keyNew key
use_tabcharsuse_tabs
max_pargs_hwrapmax_hanging_wrap_positional_args
max_subgroups_hwrapmax_hanging_wrap_groups
separate_ctrl_name_with_spacespace_before_control_paren
separate_fn_name_with_spacespace_before_definition_paren

cmakefmt fails fast on unknown config keys rather than silently ignoring them — so you will know immediately if any remain.