# How fmtlib Integrates with C++20 std::format and C++23 std::print

> Discover how fmtlib seamlessly integrates with C++20 std::format and C++23 std::print using the fmt/std.h header. Unlock powerful formatting capabilities in your C++ projects today.

- Repository: [Hello World Foundation/fmt](https://github.com/fmtlib/fmt)
- Tags: deep-dive
- Published: 2026-09-04

---

**The fmt library provides seamless interoperability with C++20 and C++23 formatting standards through the [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h) compatibility header, which exposes `std::format` and `std::print` as thin wrappers around the library's core implementation.**

The {fmt} library predates the standard formatting facilities introduced in C++20 and C++23, yet it maintains full compatibility with these newer APIs. Through a carefully designed compatibility layer, fmtlib integrates with C++20 `std::format` and C++23 `std::print` while preserving a single high-performance implementation. This allows developers to adopt standard APIs immediately while benefiting from fmt's optimized formatting engine.

## The Compatibility Layer: [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h)

The integration centers on [`include/fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/std.h), a compatibility header that bridges the gap between the fmt API and the Standard Library. When included, this header conditionally injects fmt's formatting engine into the `std` namespace based on available language features.

### Exposing `std::format` (C++20)

When the feature-test macro `__cpp_lib_format` is satisfied, [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h) brings `fmt::format` into the `std` namespace. This ensures that a call to `std::format("{:02}", 7)` compiles to the same code path as `fmt::format("{:02}", 7)`, guaranteeing identical performance and behavior. The implementation relies on the core formatting engine defined in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) and `src/format.cc`, ensuring a single source of truth for parsing and formatting logic.

### Enabling `std::print` (C++23)

For C++23 support, the header checks for the `__cpp_lib_print` macro and defines `std::print` and `std::println` as thin wrappers forwarding to `fmt::print` and `fmt::println`. This makes the new "printf-like" functions available instantly without requiring a separate Standard Library implementation. The signatures match the standard exactly, ensuring that existing code using `std::print` works unchanged while leveraging fmt's high-performance output routines.

## Implementation Architecture and Source Files

Rather than duplicating logic, fmtlib maintains one high-performance formatting core. The `std` namespace façade in [`include/fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/std.h) simply delegates to the implementation in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) and `src/format.cc`. This design eliminates code duplication while ensuring that code using `std::format` and code using `fmt::format` share the same optimized path.

Because the overloads reside in the `std` namespace but rely on the `fmt` implementation, Argument-Dependent Lookup (ADL) remains unambiguous. The architecture allows code that prefers the original `fmt::` namespace to continue compiling alongside newer code adopting the standard APIs.

## Formatter Specializations for Standard Library Types

The compatibility header provides required `formatter` specializations for Standard Library types that lack built-in support. These include `std::filesystem::path`, `std::optional`, `std::variant`, `std::expected`, and `std::source_location`. These specializations ensure that complex standard types format correctly whether you use `fmt::format` or `std::format`.

The header uses conditional compilation via `FMT_HAS_INCLUDE(<filesystem>)` to include only the specializations relevant to the current platform. This prevents compilation failures on older toolchains while ensuring modern types are supported when available.

## Conditional Compilation and ABI Safety

[`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h) uses rigorous feature detection to ensure broad compatibility across compiler versions. It checks `FMT_CPLUSPLUS >= 202002L` to determine C++20 availability and uses `__cpp_lib_print` to detect C++23 `<print>` support. The header only pulls in Standard Library facilities actually present on the target platform, maintaining ABI compatibility and preventing link-time errors.

This conditional approach means that including [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h) on a C++17 compiler causes no errors, while the same header provides full `std::format` and `std::print` support on C++23 compilers.

## Practical Code Examples

The following examples demonstrate how fmtlib enables both direct library usage and standard API compatibility.

### Using fmt Directly

This approach works on all supported compilers regardless of C++ standard version.

```cpp
#include <fmt/core.h>

int main() {
    fmt::print("Hello, {}!\n", "world");
    std::string s = fmt::format("{:04}", 42);
}

```

### Using the Standard Façade (C++20 / C++23)

Including [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h) pulls fmt into the `std` namespace when standard support is detected.

```cpp
#include <fmt/std.h>

int main() {
    std::print("Hello, {}!\n", "world");      // C++23
    std::string s = std::format("{:04}", 42); // C++20
}

```

### Formatting Standard Library Types

Standard types like `std::filesystem::path` work with both APIs thanks to the specializations in [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h).

```cpp
#include <fmt/std.h>
#include <filesystem>

int main() {
    std::filesystem::path p{"/tmp/file.txt"};
    fmt::print("Path (fmt):   {}\n", p);
    std::print("Path (std):   {}\n", p);
}

```

## Summary

- [`include/fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/std.h) serves as the compatibility bridge between fmt and Standard Library formatting APIs
- `std::format` (C++20) and `std::print` (C++23) are exposed as wrappers around `fmt::format` and `fmt::print`
- The architecture uses a single implementation core in `src/format.cc` shared by both the `fmt` and `std` namespaces
- Formatter specializations for `std::filesystem::path`, `std::optional`, `std::variant`, and other types are provided automatically
- Feature-test macros `__cpp_lib_format` and `__cpp_lib_print` enable conditional support based on compiler capabilities

## Frequently Asked Questions

### What is the purpose of [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h)?

The [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h) header provides a compatibility layer that exposes fmt's formatting implementation through the standard `std::format` and `std::print` APIs. It allows developers to write code using C++20 and C++23 standard formatting functions while utilizing fmt's high-performance backend. According to the fmtlib source code, this header also provides necessary `formatter` specializations for standard types like `std::filesystem::path` and `std::optional`.

### Does using `std::format` via fmtlib impact performance?

No, there is zero performance penalty. When you include [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h) and call `std::format`, you are invoking the exact same code path as `fmt::format`. As implemented in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) and `src/format.cc`, the standard namespace functions are thin wrappers that forward directly to the optimized fmt core. This single-source-of-truth architecture ensures identical parsing speed and memory allocation behavior between the two APIs.

### Which C++ Standard Library types gain formatter support?

The [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h) header provides formatter specializations for `std::filesystem::path`, `std::optional`, `std::variant`, `std::expected` (C++23), and `std::source_location`. These specializations are conditionally compiled based on the availability of headers like `<filesystem>` and `<optional>`, ensuring compatibility across different standard library implementations. This allows these complex types to be formatted directly in format strings without requiring manual conversion.

### How does fmtlib handle compilers without native C++23 `<print>` support?

The library uses the feature-test macro `__cpp_lib_print` to detect whether the compiler provides a native `<print>` header. If not defined, [`fmt/std.h`](https://github.com/fmtlib/fmt/blob/main/fmt/std.h) still provides `std::print` and `std::println` as wrappers around `fmt::print`, making C++23 functionality available on older compilers. This conditional compilation approach, combined with checks for `FMT_CPLUSPLUS >= 202002L`, ensures that the header compiles cleanly on C++17 while enabling full standard compliance on C++23 toolchains.