Table of Contents

  1. Presets Overview
  2. Configure Presets
  3. Build Presets
  4. Test Presets
  5. Workflow Presets
  6. User Presets
  7. Macros & Conditions
  8. Conclusion & Next Steps
Back to CMake Mastery Series

Part 23: CMake Presets

June 4, 2026 Wasil Zafar 35 min read

Standardize your build configurations with CMakePresets.json. Define configure, build, test, and workflow presets with inheritance, conditional expressions, and IDE integration for fully reproducible builds across teams.

Presets Overview

CMake Presets (introduced in CMake 3.19, extended through 3.25+) provide a JSON-based way to specify common configure, build, and test options. Instead of remembering long command lines, you define named presets that anyone on your team can use identically.

Key Insight: Before presets, teams shared build instructions in README files that quickly became outdated. CMakePresets.json is version-controlled alongside your code, making build configurations a first-class part of your project that IDEs (VS Code, CLion, Visual Studio) natively understand.

JSON Format

The presets file uses a versioned JSON schema:

# CMakePresets.json — committed to version control
{
    "version": 6,
    "cmakeMinimumRequired": {
        "major": 3,
        "minor": 25,
        "patch": 0
    },
    "configurePresets": [...],
    "buildPresets": [...],
    "testPresets": [...],
    "workflowPresets": [...]
}

File Structure

FilePurposeVersion Control
CMakePresets.jsonProject-wide presets (shared by team)Yes — commit
CMakeUserPresets.jsonPersonal developer overridesNo — .gitignore
Preset Hierarchy and Inheritance
        flowchart TD
            A[CMakePresets.json] --> B[base-config]
            B --> C[debug-config]
            B --> D[release-config]
            B --> E[ci-config]
            C --> F[debug-build]
            D --> G[release-build]
            E --> H[ci-build]
            F --> I[debug-test]
            G --> J[release-test]
            H --> K[ci-test]
            L[CMakeUserPresets.json] --> M[my-local-config]
            M -->|inherits| B
    

Configure Presets

Configure presets define how cmake -S . -B build runs — the generator, cache variables, environment, and toolchain:

Generators and Cache Variables

{
    "version": 6,
    "configurePresets": [
        {
            "name": "base",
            "hidden": true,
            "binaryDir": "${sourceDir}/build/${presetName}",
            "cacheVariables": {
                "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
                "BUILD_TESTING": "ON"
            }
        },
        {
            "name": "linux-debug",
            "inherits": "base",
            "displayName": "Linux Debug",
            "description": "Debug build with GCC on Linux",
            "generator": "Ninja",
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "Debug",
                "CMAKE_C_COMPILER": "gcc",
                "CMAKE_CXX_COMPILER": "g++",
                "ENABLE_SANITIZERS": "ON"
            },
            "environment": {
                "CXXFLAGS": "-fdiagnostics-color=always"
            }
        },
        {
            "name": "linux-release",
            "inherits": "base",
            "displayName": "Linux Release",
            "generator": "Ninja",
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "Release",
                "CMAKE_C_COMPILER": "gcc",
                "CMAKE_CXX_COMPILER": "g++",
                "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON"
            }
        },
        {
            "name": "windows-msvc",
            "inherits": "base",
            "displayName": "Windows MSVC",
            "generator": "Visual Studio 17 2022",
            "architecture": {
                "value": "x64",
                "strategy": "set"
            },
            "cacheVariables": {
                "CMAKE_INSTALL_PREFIX": "${sourceDir}/install"
            }
        }
    ]
}
# List available presets
cmake --list-presets

# Configure using a preset
cmake --preset linux-debug

# Equivalent to:
# cmake -S . -B build/linux-debug -G Ninja \
#   -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=gcc ...

Toolchain File Integration

{
    "name": "arm-cross",
    "inherits": "base",
    "displayName": "ARM Cross-Compilation",
    "toolchainFile": "${sourceDir}/cmake/toolchains/arm-none-eabi.cmake",
    "cacheVariables": {
        "CMAKE_BUILD_TYPE": "MinSizeRel"
    }
}

Inheritance

Presets support single and multiple inheritance to avoid duplication:

{
    "name": "ci-linux-release",
    "inherits": ["linux-release", "ci-base"],
    "displayName": "CI Linux Release",
    "cacheVariables": {
        "BUILD_DOCS": "ON",
        "ENABLE_COVERAGE": "OFF"
    }
}
Hands-On Create Your First Preset
Multi-Platform Presets

Create a CMakePresets.json that supports both Debug and Release on Linux with Ninja:

# Create the presets file at project root
cat > CMakePresets.json << 'EOF'
{
    "version": 6,
    "configurePresets": [
        {
            "name": "dev",
            "displayName": "Development",
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/build/dev",
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "Debug",
                "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
            }
        },
        {
            "name": "release",
            "displayName": "Release",
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/build/release",
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "Release"
            }
        }
    ],
    "buildPresets": [
        {"name": "dev", "configurePreset": "dev"},
        {"name": "release", "configurePreset": "release"}
    ]
}
EOF

# Use it
cmake --preset dev
cmake --build --preset dev
CMakePresets.json Ninja multi-config

Build Presets

Build presets define how cmake --build executes — targets, parallelism, and configuration:

"buildPresets": [
    {
        "name": "linux-debug-build",
        "configurePreset": "linux-debug",
        "jobs": 8,
        "targets": ["all"],
        "verbose": false
    },
    {
        "name": "linux-release-build",
        "configurePreset": "linux-release",
        "jobs": 0,
        "configuration": "Release",
        "cleanFirst": false
    },
    {
        "name": "docs-only",
        "configurePreset": "linux-debug",
        "targets": ["docs"],
        "inherits": "linux-debug-build"
    }
]
# Build using preset
cmake --build --preset linux-debug-build

# List build presets
cmake --build --list-presets

Test Presets

Test presets configure ctest execution:

"testPresets": [
    {
        "name": "linux-debug-test",
        "configurePreset": "linux-debug",
        "output": {
            "outputOnFailure": true,
            "verbosity": "default"
        },
        "execution": {
            "jobs": 8,
            "timeout": 300,
            "stopOnFailure": false
        }
    },
    {
        "name": "unit-tests-only",
        "configurePreset": "linux-debug",
        "filter": {
            "include": {
                "label": "unit"
            },
            "exclude": {
                "label": "integration|slow"
            }
        }
    },
    {
        "name": "ci-test",
        "configurePreset": "ci-linux-release",
        "output": {
            "outputOnFailure": true,
            "outputJUnitFile": "test-results.xml"
        },
        "execution": {
            "jobs": 4,
            "repeatMode": "until-pass",
            "repeatCount": 3
        }
    }
]
# Run tests using preset
ctest --preset linux-debug-test

# Run only unit tests
ctest --preset unit-tests-only

Workflow Presets

Workflow presets (CMake 3.25+) chain configure → build → test into a single command:

"workflowPresets": [
    {
        "name": "full-ci",
        "displayName": "Full CI Pipeline",
        "steps": [
            {"type": "configure", "name": "ci-linux-release"},
            {"type": "build", "name": "linux-release-build"},
            {"type": "test", "name": "ci-test"}
        ]
    },
    {
        "name": "dev-cycle",
        "displayName": "Developer Build + Test",
        "steps": [
            {"type": "configure", "name": "linux-debug"},
            {"type": "build", "name": "linux-debug-build"},
            {"type": "test", "name": "unit-tests-only"}
        ]
    }
]
# Execute entire workflow
cmake --workflow --preset full-ci

# Developer quick cycle
cmake --workflow --preset dev-cycle
Version Requirement: Workflow presets require schema version 6 (CMake 3.25+). Check your CMake version with cmake --version and update if needed.

CMakeUserPresets.json

Personal presets that shouldn't be committed (add to .gitignore):

# CMakeUserPresets.json — NOT committed to git
{
    "version": 6,
    "configurePresets": [
        {
            "name": "my-debug",
            "inherits": "linux-debug",
            "displayName": "My Local Debug",
            "cacheVariables": {
                "CMAKE_C_COMPILER": "/opt/gcc-14/bin/gcc",
                "CMAKE_CXX_COMPILER": "/opt/gcc-14/bin/g++",
                "VCPKG_ROOT": "/home/dev/vcpkg"
            },
            "environment": {
                "CC": "/opt/gcc-14/bin/gcc",
                "CXX": "/opt/gcc-14/bin/g++"
            }
        }
    ]
}
# .gitignore entry
CMakeUserPresets.json
Hands-On Workflow Automation
Complete CI Workflow Preset

Set up a workflow that mirrors your CI pipeline locally:

# Run the full CI pipeline locally
cmake --workflow --preset full-ci

# Output:
# -- Configuring preset 'ci-linux-release'...
# -- Building preset 'linux-release-build'...
# -- Testing preset 'ci-test'...
# 100% tests passed, 0 tests failed out of 47

This eliminates "works on my machine" problems — the same presets run in CI and locally.

workflow CI reproducible

Macros & Conditions

Presets support macro expansion and conditional expressions for dynamic configuration:

{
    "name": "platform-aware",
    "binaryDir": "${sourceDir}/build/${presetName}",
    "cacheVariables": {
        "CMAKE_INSTALL_PREFIX": "$env{HOME}/opt/myapp",
        "PROJECT_DATA_DIR": "${sourceDir}/data"
    },
    "environment": {
        "PATH": "$penv{PATH}:${sourceDir}/tools"
    },
    "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Linux"
    }
}

Available macros:

MacroExpands To
${sourceDir}Path to source directory
${sourceParentDir}Parent of source directory
${presetName}Name of the current preset
${generator}Generator name
${hostSystemName}Host OS (Linux, Windows, Darwin)
$env{VAR}Environment variable value
$penv{VAR}Parent environment (for prepending)
$vendor{key}Vendor-specific macro
IDE Preset Integration
        flowchart LR
            A[CMakePresets.json] --> B[VS Code CMake Tools]
            A --> C[CLion]
            A --> D[Visual Studio 2022]
            A --> E[Qt Creator]
            B --> F[Kit Selection = Preset]
            C --> G[Profiles from Presets]
            D --> H[CMake Settings]
            E --> I[Build Configuration]
            F --> J[cmake --preset dev]
            G --> J
            H --> J
            I --> J
    
Hands-On Conditional Presets
Platform-Specific Preset with Conditions
{
    "name": "macos-arm",
    "inherits": "base",
    "displayName": "macOS ARM64",
    "generator": "Ninja",
    "condition": {
        "type": "allOf",
        "conditions": [
            {"type": "equals", "lhs": "${hostSystemName}", "rhs": "Darwin"},
            {"type": "matches", "string": "$env{PROCESSOR_ARCHITECTURE}", "regex": "arm64|aarch64"}
        ]
    },
    "cacheVariables": {
        "CMAKE_OSX_ARCHITECTURES": "arm64",
        "CMAKE_BUILD_TYPE": "Release"
    }
}

This preset only appears in cmake --list-presets when running on macOS ARM64 hardware.

conditions platform macros

Conclusion & Next Steps

CMake Presets eliminate configuration drift and make builds reproducible across machines and CI systems. Key takeaways:

  • CMakePresets.json goes in version control; CMakeUserPresets.json stays local
  • Use inherits to compose presets and avoid duplication
  • Workflow presets chain configure → build → test into one command
  • All major IDEs natively read CMakePresets.json for kit/profile selection
  • Conditions gate presets to specific platforms or environments
Official Reference: See the complete cmake-presets(7) manual for all preset fields, conditions, and version history.