# How to Migrate from Catch2 v2 to v3: Single-Header to Multi-Header Guide

> Easily migrate from Catch2 v2 to v3. Update your includes, link Catch2 CMake targets, and adjust matcher namespaces for a smooth transition from single-header to multi-header.

- Repository: [Catch Org/Catch2](https://github.com/catchorg/Catch2)
- Tags: migration-guide
- Published: 2026-07-29

---

**To migrate from Catch2 v2 to v3, replace the monolithic `<catch2/catch.hpp>` include with `<catch2/catch_all.hpp>` or fine-grained headers like `<catch2/catch_test_macros.hpp>`, link against the `Catch2::Catch2` CMake target instead of using header-only compilation, and update matcher namespaces to `Catch::Matchers`.**

Catch2 v3 introduces a fundamental architectural change in the `catchorg/Catch2` repository, moving away from the single-header distribution model toward a modular multi-header structure compiled as a static library. This shift reduces compilation times by approximately 80% but requires updates to your build system configuration, include directives, and in some cases, minor code adjustments for breaking changes.

## Key Architectural Changes in Catch2 v3

The most significant difference between v2 and v3 is the header organization and build model. According to the Catch2 source code, the monolithic `<catch2/catch.hpp>` has been replaced by a focused header structure centered around [`src/catch2/catch_all.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_all.hpp) as the umbrella header.

**Static library compilation** is now the default distribution method. Rather than compiling Catch2's implementation into every translation unit that includes the header (header-only mode), you now link against pre-compiled static library targets: `Catch2` (library only) or `Catch2WithMain` (library including the default `main()` function). This change, implemented in the CMake configuration at the repository root, dramatically improves build performance by eliminating redundant parsing and compilation of template-heavy code.

**C++14 minimum requirement** is now enforced throughout the codebase. All code in `src/catch2/` assumes at least C++14 support, requiring compiler upgrades for projects previously targeting C++11.

## Migration Strategies

You have two approaches when migrating from the v2 single-header model to v3.

### Option 1: Amalgamated Files (Transition Path)

For projects that need minimal build system changes, Catch2 v3 provides amalgamated files in the `extras/` directory. These files combine the new multi-header structure into two files: [`extras/catch_amalgamated.hpp`](https://github.com/catchorg/Catch2/blob/main/extras/catch_amalgamated.hpp) and [`extras/catch_amalgamated.cpp`](https://github.com/catchorg/Catch2/blob/main/extras/catch_amalgamated.cpp).

Copy these files into your project and replace your v2 include:

```cpp
// Old v2 single-header
#include <catch2/catch.hpp>

// New v3 amalgamated
#include "catch_amalgamated.hpp"

```

This approach works immediately but sacrifices the compile-time benefits of the static library model, as it reverts to header-only compilation with longer build times.

### Option 2: Full Static Library Integration (Recommended)

The recommended approach involves consuming Catch2 as a compiled static library. This requires updating your CMake configuration and include statements to leverage the modular headers in `src/catch2/`, allowing the compiler to process only the declarations your test files actually use.

## Step-by-Step CMake Migration

Update your [`CMakeLists.txt`](https://github.com/catchorg/Catch2/blob/main/CMakeLists.txt) to use the exported targets instead of header-only includes.

```cmake

# Catch2 v2 (header-only)

add_executable(tests test.cpp)
target_link_libraries(tests PRIVATE catch2)

# Catch2 v3 (static library)

find_package(Catch2 CONFIG REQUIRED)
add_executable(tests test.cpp)
target_link_libraries(tests PRIVATE Catch2::Catch2)

# OR use Catch2::Catch2WithMain to have Catch2 provide main()

```

If you use `Catch2::Catch2WithMain`, remove any translation unit that defines `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`. The library now provides the entry point automatically through the linked archive.

## Updating Header Includes

Replace the single v2 header with either the v3 umbrella header or selective includes for finer build performance.

**Using the umbrella header:**

```cpp
// Replace this v2 include
#include <catch2/catch.hpp>

// With this v3 include
#include <catch2/catch_all.hpp>

```

**Using fine-grained headers (recommended):**

```cpp
#include <catch2/catch_test_macros.hpp>        // Core macros: TEST_CASE, SECTION, REQUIRE
#include <catch2/matchers/catch_matchers_all.hpp>  // Matchers interface
#include <catch2/generators/catch_generators_all.hpp>  // Data generators

```

Selective inclusion from `src/catch2/` allows the compiler to process only the declarations your test files actually need, further reducing build times compared to the umbrella header approach.

## Handling Breaking Changes in Catch2 v3

Several interfaces changed between v2 and v3 that require code updates beyond include paths.

**Matcher namespace restructuring:** All matchers now reside in the `Catch::Matchers` namespace, and some names changed to be more specific. For example, the string matcher `Contains` is now `ContainsSubstring`. Update your code accordingly:

```cpp
// v2 syntax
REQUIRE_THAT(str, Catch::Contains("substring"));

// v3 syntax
#include <catch2/matchers/catch_matchers_all.hpp>
REQUIRE_THAT(str, Catch::Matchers::ContainsSubstring("substring"));

```

**Custom reporters and listeners:** If you implemented custom reporters, note that the interfaces have changed significantly in v3. Consult the [`docs/reporters.md`](https://github.com/catchorg/Catch2/blob/main/docs/reporters.md) and [`docs/reporter-events.md`](https://github.com/catchorg/Catch2/blob/main/docs/reporter-events.md) files in the repository for updated base class signatures and event handling.

## Complete Migration Example

Here is a complete before-and-after comparison for a typical test file.

**Catch2 v2 (test.cpp):**

```cpp
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>

TEST_CASE("Vector contains element") {
    std::vector<int> v{1, 2, 3};
    REQUIRE_THAT(v, Catch::Contains(2));
}

```

**Catch2 v3 (test.cpp):**

```cpp
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_all.hpp>

using Catch::Matchers::Contains;

TEST_CASE("Vector contains element") {
    std::vector<int> v{1, 2, 3};
    REQUIRE_THAT(v, Contains(2));
}

```

**CMakeLists.txt (v3):**

```cmake
cmake_minimum_required(VERSION 3.16)
project(MyTests)

find_package(Catch2 CONFIG REQUIRED)

add_executable(tests test.cpp)
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain)

```

## Summary

- **Replace** `<catch2/catch.hpp>` with `<catch2/catch_all.hpp>` or granular headers from `src/catch2/`
- **Link** against `Catch2::Catch2` or `Catch2::Catch2WithMain` CMake targets instead of header-only usage
- **Remove** custom `main()` definitions when using `Catch2::Catch2WithMain`
- **Update** matcher namespaces to `Catch::Matchers` and replace deprecated names like `Contains` with `ContainsSubstring` for string matching
- **Require** C++14 minimum for all compilation units consuming Catch2 headers

## Frequently Asked Questions

### Do I have to use CMake to migrate to Catch2 v3?

No, CMake is not strictly required, though it is the primary supported build system for the `catchorg/Catch2` repository. You can compile the source files in `src/catch2/` manually into a static library using your preferred build system and link it to your test executables. However, using CMake with the exported `Catch2::Catch2` target handles include directories and transitive dependencies automatically, making it the recommended approach.

### What happened to CATCH_CONFIG_MAIN in Catch2 v3?

`CATCH_CONFIG_MAIN` is no longer necessary if you link against the `Catch2::Catch2WithMain` target, which provides its own `main()` function implementation in the static library. If you define your own `main()` function for custom setup, link against `Catch2::Catch2` instead. If you use the amalgamated header approach, you still define `CATCH_CONFIG_MAIN` in exactly one translation unit as in v2.

### How do I fix matcher compilation errors after migrating?

Matcher-related errors usually indicate namespace issues or renamed interfaces. In v3, all matchers moved to the `Catch::Matchers` namespace, and some specific matchers were renamed (e.g., `Contains` became `ContainsSubstring` for string matching). Include `<catch2/matchers/catch_matchers_all.hpp>` from `src/catch2/` and qualify matcher names with `Catch::Matchers::` or use specific `using` declarations to resolve these errors.

### Can I still use Catch2 v3 as a single-header library?

Yes, through the amalgamated files provided in [`extras/catch_amalgamated.hpp`](https://github.com/catchorg/Catch2/blob/main/extras/catch_amalgamated.hpp) and [`extras/catch_amalgamated.cpp`](https://github.com/catchorg/Catch2/blob/main/extras/catch_amalgamated.cpp). Copy both files to your project, include the header, and compile the `.cpp` file alongside your tests. However, this approach compiles Catch2's implementation into every translation unit that includes the header, negating the approximately 80% compile-time improvement offered by the static library model in `src/catch2/`.