# What Does the FMT_HEADER_ONLY Macro Do and When Should You Use It?

> Discover the FMT_HEADER_ONLY macro from fmtlib. Learn how it enables header-only mode for C++ formatting, inlining all code and simplifying your build process without library linking.

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

---

**The `FMT_HEADER_ONLY` macro switches the {fmt} library into header-only mode, inlining all implementation code directly into your translation units and eliminating the need to link against a compiled library.**

The `{fmt}` library typically builds as a separate compiled target that you link into your application. According to the fmtlib/fmt source code, the `FMT_HEADER_ONLY` preprocessor macro provides a zero-linkage alternative that moves all implementation code directly into the headers through conditional compilation guards. Understanding when to enable this macro helps you balance build simplicity against compilation overhead in modern C++ projects.

## What Is the FMT_HEADER_ONLY Macro?

`FMT_HEADER_ONLY` is a preprocessor definition that disables external symbol export for the {fmt} library. When this macro is defined before including any {fmt} headers, the library stops exporting compiled symbols and instead makes all template instantiations, formatting functions, and utility implementations available directly from the header files.

In the source repository, this behavior is orchestrated through `#ifndef FMT_HEADER_ONLY` guards found in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h), [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h), and [`include/fmt/fmt-c.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/fmt-c.h). For example, in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) (approximately lines 1351–1360), blocks of code responsible for exporting symbols to the compiled library are wrapped in these guards, ensuring they are only active when the macro is **not** defined.

The CMake build system explicitly defines this macro in [`CMakeLists.txt`](https://github.com/fmtlib/fmt/blob/main/CMakeLists.txt) (around line 420) through the command `target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)`. This creates the `fmt-header-only` target, which automatically injects the definition into any target that links against it.

## Header-Only Mode vs. Compiled Library Mode

Understanding the distinction between these two modes helps you choose the right integration strategy for your project.

**Compiled Library Mode (Default)**
When `FMT_HEADER_ONLY` is undefined, the library compiles as a separate binary target (`fmt`). The headers contain only declarations, and the actual implementation code resides in compiled object files. This approach minimizes compile times for projects that include {fmt} headers in multiple translation units and produces smaller individual object files.

**Header-Only Mode**
When `FMT_HEADER_ONLY` is defined, the guarded sections in headers like [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h) and [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) expose the full implementations. Every translation unit that includes these headers compiles the {fmt} code locally, resulting in a standalone binary with no external library dependency. This mode eliminates the linking step but increases compilation overhead.

## When to Use FMT_HEADER_ONLY

Enable the `FMT_HEADER_ONLY` macro in the following scenarios:

- **Simple scripts and single-file projects**: When you want to use {fmt} without setting up a build system to compile and link the library.
- **Embedded environments**: On toolchains that cannot easily produce or link static libraries, or where distributing a single set of headers is preferable to managing binaries.
- **Rapid prototyping**: When you need immediate functionality without configuring CMake, pkg-config, or linker flags.
- **Header-only library constraints**: When integrating {fmt} into another header-only library where introducing a compiled dependency would violate the header-only contract.

**Performance and Build Considerations**
Using header-only mode typically **increases compile times** because the compiler must process the full {fmt} implementation in every translation unit that includes the headers. This can also lead to slightly larger total binary sizes if multiple object files contain duplicate template instantiations. For large projects with many source files, the compiled library mode offers better build performance.

## Implementation Examples

The following examples demonstrate how to activate header-only mode manually and through CMake.

### Manual Macro Definition

Define the macro before the first {fmt} include to enable header-only mode for that translation unit:

```cpp
#define FMT_HEADER_ONLY
#include <fmt/format.h>

int main() {
    fmt::print("Hello, {}!\n", "header-only world");
    // No -lfmt or fmt.lib required during linking
}

```

### Using the CMake Target

Link against the `fmt-header-only` target to automatically apply the macro definition across your project:

```cmake
cmake_minimum_required(VERSION 3.8)
project(example)

add_subdirectory(fmt)  # Assuming fmt source is available

add_executable(app main.cpp)
target_link_libraries(app PRIVATE fmt-header-only)

```

This approach defines `FMT_HEADER_ONLY=1` via the target's interface compile definitions, as implemented in [`CMakeLists.txt`](https://github.com/fmtlib/fmt/blob/main/CMakeLists.txt) at line 420.

### Checking the Current Mode

You can verify the mode at compile time if needed:

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

#ifdef FMT_HEADER_ONLY
    // Code specific to header-only builds
#endif

```

## Key Source Files

The header-only mechanism is implemented across these critical files in the fmtlib/fmt repository:

- **[`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h)**: Contains the primary formatting logic and guarded export blocks (lines ~1351–1360) that control symbol visibility based on `FMT_HEADER_ONLY`.
- **[`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h)**: Houses low-level utilities and type definitions with similar conditional compilation guards.
- **[`include/fmt/fmt-c.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/fmt-c.h)**: Manages Windows-specific definitions and exports using the same macro checks.
- **[`CMakeLists.txt`](https://github.com/fmtlib/fmt/blob/main/CMakeLists.txt)**: Defines the `fmt-header-only` CMake target and sets `FMT_HEADER_ONLY=1` as an interface compile definition around line 420.

## Summary

- The `FMT_HEADER_ONLY` macro enables header-only mode for the {fmt} library, eliminating the need to link against `libfmt`.
- When defined, implementation code in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) and related headers becomes active, while symbol exports are disabled.
- Use this macro for simple projects, embedded systems, or when you cannot manage compiled library dependencies.
- Prefer the compiled library mode for large projects to minimize compile times and binary bloat.
- The CMake target `fmt-header-only` automatically configures this macro for your build.

## Frequently Asked Questions

### Does FMT_HEADER_ONLY affect runtime performance?

No, the `FMT_HEADER_ONLY` macro does not change the runtime performance characteristics of {fmt}. The same optimization opportunities exist in both modes because the compiler sees identical implementation code. The primary differences are build-time compile duration and whether the code resides in a separate library or is duplicated across translation units.

### Can I mix header-only and compiled modes in the same project?

No, you should not mix these modes within a single program. If one translation unit includes {fmt} headers with `FMT_HEADER_ONLY` defined and another links against the compiled `fmt` library, you risk violating the One Definition Rule (ODR) and encountering linker errors due to duplicate symbol definitions. Choose one approach for the entire project.

### How do I migrate from header-only to compiled library mode?

Remove the `#define FMT_HEADER_ONLY` directive from your source files (or switch from `fmt-header-only` to the `fmt` CMake target), then ensure you link against the compiled library. In CMake, change `target_link_libraries(target PRIVATE fmt-header-only)` to `target_link_libraries(target PRIVATE fmt)`. You may need to add `find_package(fmt)` or `add_subdirectory(fmt)` depending on your setup.

### Is FMT_HEADER_ONLY required when using {fmt} with package managers?

No, when installing {fmt} through package managers like Conan, vcpkg, or system package managers, you typically receive the compiled library by default. The `FMT_HEADER_ONLY` macro is only necessary if you specifically want header-only behavior or are copying the source headers directly into your project without building the library.