CMake Presets for Reproducible Builds Without Tribal Knowledge
CMake Presets capture configure and build settings in JSON to replace tribal command lines. Learn how to use inheritance, conditions and user presets for reproducible builds with practical limits and verification steps.
24 May 2026, 04:13 UTC

The onboarding problem presets solve
A new contributor clones the repo and asks "how do I build this?" The answer is a 120-character cmake invocation with generator flags, toolchain path, cache variables and build type. CI uses a slightly different set. The result is drift between laptops and pipelines, and debugging starts with command history instead of code.
CMake Presets is a JSON-based, read-only way to declare configure, build and test settings once in the repository. The thesis is simple: keep the long invocation in CMakePresets.json, not in Slack threads. Developers run cmake --preset <name> and CI runs the same name.
What presets capture and where they live
Presets are declared in CMakePresets.json at the project root and optionally overridden locally in CMakeUserPresets.json. The file is declarative and does not modify CMakeLists.txt. It can express configurePresets with generator, toolchainFile, cacheVariables and environment, and buildPresets that reference a configure preset.
Key mechanisms for engineering use:
inheritsto share a base preset and override only what changes per platform.conditionto enable a preset only when an environment variable or CMake variable is present.- Separation of shared defaults in
CMakePresets.jsonfrom personal paths inCMakeUserPresets.json, so secrets and local install prefixes are not committed.
Presets are version sensitive. The full feature set stabilised around CMake 3.19-3.21 with later additions. Older CMake versions silently ignore unknown fields, which leads to confusing configure failures. Check compatibility with cmake --version and the schemaVersion in the file.
Worked example: platform presets with inheritance
Run the following in a project root that already contains CMakeLists.txt. No elevated permissions are required.
cmake --list-presets
Expected check: the tool lists configure and build presets by name and shows inheritance.
A minimal shared preset file can look like this:
{
"version": 3,
"configurePresets": [
{
"name": "base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"MYPROJECT_ENABLE_TESTS": "ON"
}
},
{
"name": "linux-clang",
"inherits": "base",
"condition": {"type": "equals", "lhs": "${hostSystemName}", "rhs": "Linux"},
"toolchainFile": "${sourceDir}/cmake/toolchains/clang-linux.cmake",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
}
},
{
"name": "windows-msvc",
"inherits": "base",
"condition": {"type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows"},
"generator": "Visual Studio 17 2022",
"architecture": "x64"
}
],
"buildPresets": [
{
"name": "linux-clang",
"configurePreset": "linux-clang"
},
{
"name": "windows-msvc",
"configurePreset": "windows-msvc"
}
]
}
Configure with:
cmake --preset linux-clang
After configure, inspect build/linux-clang/CMakeCache.txt to confirm CMAKE_TOOLCHAIN_FILE and cache variables match the preset. Build with:
cmake --build --preset linux-clang
Risk: Presets do not replace toolchain files. Complex cross-compilation still requires a correct toolchain file referenced from the preset. A misconfigured toolchain is only detected at configure time.
Trade-offs and limits in practice
Condition expressions are evaluated when presets are read, not during configure. If an environment variable is missing on CI, the preset can disappear from cmake --list-presets with no obvious error.
CMakeUserPresets.json is user-local and not version controlled. Teams need a documented template or generation step for onboarding, otherwise developers create divergent local presets.
Because presets are JSON, they cannot express arbitrary CMake logic. Keep complex logic in CMakeLists.txt or toolchain files and use presets only for stable configuration choices.
Actionable adoption
Start with one shared base configure preset and one per-platform preset. Commit CMakePresets.json and add a CMakeUserPresets.template.json for local overrides. Document the required CMake minimum version and verify with cmake --version before CI runs.
Verify adoption by running cmake --list-presets on a clean checkout, configuring with cmake --preset <name>, and confirming cache variables and toolchain in CMakeCache.txt. If the preset list changes unexpectedly, check environment variables used in conditions.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.