# What Is FMT_HEADER_ONLY? Benefits of Header-Only Mode in fmtlib

> Explore the benefits of FMT_HEADER_ONLY mode in fmtlib. Eliminate library linking by instantiating templates inline for faster builds and simpler project setup.

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

---

**Defining `FMT_HEADER_ONLY` switches {fmt} to a header-only configuration that eliminates the need to link against a separate library binary by instantiating all formatting templates inline within each translation unit.**

The {fmt} library provides fast, type-safe text formatting for C++. By default, it compiles into a standalone library (`libfmt`) that you link against your application. However, the `FMT_HEADER_ONLY` preprocessor macro offers an alternative compilation model that embeds the entire library directly into your source code, providing distinct advantages for specific deployment scenarios.

## How FMT_HEADER_ONLY Works Internally

When you define `FMT_HEADER_ONLY`, you change how the compiler handles template instantiation. In the standard compiled mode, {fmt} uses explicit template instantiations declared with `extern template` to minimize compilation overhead. These declarations appear in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) at lines 1351–1360, where they instruct the compiler to expect定型版 (pre-compiled) template instances in the linked library.

```cpp
// From include/fmt/format.h (lines 1351-1360)
#ifndef FMT_HEADER_ONLY

#  define FMT_EXTERN template

   extern template struct FMT_INSTANTIATION_DEF_API detail::basic_data<void>;
   // ... additional extern template declarations
#else

#  define FMT_EXTERN

#endif

```

When `FMT_HEADER_ONLY` is defined, the preprocessor skips these `extern template` guards. Consequently, the full template definitions remain visible in the header, forcing the compiler to generate inline instantiations in every translation unit that includes the library. This mechanism effectively converts {fmt} from a compiled binary dependency into a header-only library similar to single-file utilities.

## Five Key Benefits of Using FMT_HEADER_ONLY

### No Separate Library Binary Required

The most immediate benefit is the elimination of the linking step. You no longer need to build or distribute `libfmt`, whether as a static (`.a`/`.lib`) or shared (`.so`/`.dll`) object. This is particularly valuable for embedded systems environments or educational projects where managing compiled dependencies adds unnecessary complexity. As implemented in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h), the macro ensures all implementation details remain available to the compiler without requiring external symbols.

### Faster Build Times for Small Projects

Single-file utilities and small applications often compile faster in header-only mode because they bypass the overhead of building a separate library target. According to the CMake configuration in [`CMakeLists.txt`](https://github.com/fmtlib/fmt/blob/main/CMakeLists.txt) at line 456, the `fmt-header-only` interface target simply adds the macro definition without producing a compiled artifact:

```cmake

# CMakeLists.txt defines the header-only target

target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)

```

This eliminates the need to compile the library's translation units separately and streamlines the build graph in monolithic projects.

### Reduced Binary Size via Dead Code Elimination

Header-only mode enables aggressive dead code elimination. Because templates are instantiated on-demand rather than pulled from a pre-compiled library, the linker sees only the specific formatting functions your code actually uses. Unused specializations—such as exotic floating-point formatters or wide-character handlers—can be discarded during the linking phase. The {fmt} README highlights this characteristic in its "Small code size" section, noting that header-only usage allows the compiler to strip away unused formatting machinery that would otherwise remain in a monolithic library binary.

### Simplified Cross-Platform Dependency Management

Distributing compiled binaries across heterogeneous environments (Windows, Linux, macOS, various embedded targets) requires managing platform-specific artifacts and ABI compatibility. `FMT_HEADER_ONLY` removes this burden entirely. Since the implementation resides solely in headers ([`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)), a single source tree works everywhere the compiler supports C++11 or later. This portability is documented in [`doc/api.md`](https://github.com/fmtlib/fmt/blob/main/doc/api.md) (lines 83–85), which lists the macro as a configuration option for projects requiring maximum portability without additional artifacts.

### Seamless Integration with Header-Only Ecosystems

Modern C++ projects often rely on header-only libraries like `nlohmann/json` or `spdlog` to minimize dependency friction. `FMT_HEADER_ONLY` allows {fmt} to fit naturally into these ecosystems. The macro is detected early in the preprocessor phase (around line 4607 in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h)), enabling the same source tree to function as either a compiled library or a drop-in header-only dependency based on a single configuration flag.

## Implementation Examples

### Manual Macro Definition

To use {fmt} as a pure header-only library, define the macro before including any headers:

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

int main() {
    // No need to link against libfmt
    fmt::print("Hello, {}!\n", "world");
    std::string s = fmt::format("Answer: {}", 42);
    fmt::print("{}\n", s);
}

```

This approach requires no changes to your build system beyond ensuring the `include` directory is in your compiler's search path.

### CMake Configuration

For CMake-based projects, use the provided interface target rather than manually defining the macro:

```cmake
cmake_minimum_required(VERSION 3.14)
project(myapp)

find_package(fmt REQUIRED)
add_executable(myapp main.cpp)

# Use the header-only interface target

target_link_libraries(myapp PRIVATE fmt::fmt-header-only)

```

The `fmt::fmt-header-only` target automatically propagates the `FMT_HEADER_ONLY` definition and include directories to your executable.

### Conditional Compilation

For libraries that must support both compiled and header-only modes, conditionally include the macro:

```cpp
#if defined(FMT_HEADER_ONLY)
    #include <fmt/format.h>
#else
    #include <fmt/format.h>
    #pragma comment(lib, "fmt")   // Windows MSVC example
#endif

```

This pattern allows downstream consumers to choose their preferred linking strategy without modifying your library's source code.

## Summary

- **`FMT_HEADER_ONLY`** converts {fmt} from a compiled library into a header-only dependency by disabling `extern template` declarations in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h).
- **Zero linking required**: Eliminates the need to build or distribute `libfmt` binaries, simplifying deployment across platforms.
- **Optimized binaries**: Template instantiation on-demand enables the linker to discard unused formatting code, reducing executable size.
- **Faster iteration**: Small projects benefit from streamlined build processes without separate library compilation steps.
- **CMake support**: The `fmt::fmt-header-only` target provides idiomatic integration for modern build systems.

## Frequently Asked Questions

### What is the difference between `FMT_HEADER_ONLY` and the compiled library?

The compiled library pre-instantiates common template specializations and exports them as symbols in `libfmt`, requiring you to link against the binary. `FMT_HEADER_ONLY` keeps all template definitions in the headers ([`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) and [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h)), causing the compiler to generate code inline for each translation unit. This trades potentially larger object files for the convenience of header-only distribution.

### Does `FMT_HEADER_ONLY` increase compilation times?

For small projects with few translation units, header-only mode often reduces total build time by eliminating the library compilation step. However, for large codebases with hundreds of translation units all including {fmt} headers, the repeated template instantiation may increase overall compilation time compared to linking against a pre-compiled library. The impact depends on your project's structure and compiler optimization settings.

### When should I avoid using `FMT_HEADER_ONLY`?

Avoid header-only mode when binary size is critical and your application uses {fmt} across many translation units, as each unit will contain its own copy of the template instantiations. Additionally, if you need to minimize compile times in large projects or if you're distributing {fmt} as a system package where ABI stability matters, the compiled library provides better isolation and faster incremental builds.

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

Migration requires two steps: first, add `#define FMT_HEADER_ONLY` before your include statements or switch to the `fmt::fmt-header-only` CMake target; second, remove `libfmt` from your linker flags and dependency lists. Verify that your build system no longer references the compiled library artifacts, and ensure all translation units that include {fmt} headers have access to the macro definition to avoid One Definition Rule (ODR) violations.