# How fmtlib Implements Compile-Time Format String Parsing with compile.h

> Discover how fmtlib uses compile time format string parsing with compile.h. Learn about constexpr utilities template metaprogramming and a recursive parser for efficient string formatting.

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

---

**fmtlib achieves compile-time format string parsing through constexpr utilities, template metaprogramming, and a recursive parser that converts format strings into compile-time AST nodes defined in [`include/fmt/compile.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/compile.h).**

The fmt library eliminates runtime formatting overhead by processing format strings at compile time using modern C++ features. The header [`include/fmt/compile.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/compile.h) provides the machinery to transform string literals into type-safe, pre-parsed objects that encode formatting logic directly into the type system.

## Overview of the Compile-Time Parsing Architecture

The implementation relies on marking string literals as **compiled strings**, then recursively parsing them at compile time to build an abstract syntax tree (AST) represented as C++ types. Each node in this tree—from text fragments to replacement fields—carries its own `constexpr format` method that writes directly to output iterators.

When you invoke `fmt::format` with a compiled string, the library bypasses the runtime parser entirely. Instead, it instantiates the pre-built type hierarchy, executing only the `format` methods of the generated AST nodes.

## Triggering Compile-Time Parsing with FMT_COMPILE

The primary entry point is the `FMT_COMPILE(s)` macro defined at **line 37** of [`include/fmt/compile.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/compile.h). When the compiler supports `if constexpr` and return type deduction, this macro expands to `FMT_STRING_IMPL(s, fmt::compiled_string)`, effectively tagging the literal for compile-time processing.

```cpp
// This macro marks the string for compile-time parsing
std::string s = fmt::format(FMT_COMPILE("Result: {}"), 42);

```

This expansion ensures that the format string undergoes parsing during compilation rather than at runtime.

## Marking and Detecting Compiled Strings

To distinguish compiled strings from runtime strings, the library uses a marker class and type trait defined at **lines 20-24**:

```cpp
class compiled_string {};

template<class S>
struct is_compiled_string : std::is_base_of<compiled_string, S> {};

```

The `compiled_string` class serves as an empty base class, while `is_compiled_string` leverages `std::is_base_of` to detect the special type. When `fmt::format` receives a first argument satisfying `is_compiled_string`, it immediately routes the call to the compile-time code path.

## The Recursive Constexpr Parser

Once a compiled string is detected, `detail::compile<T...>(S{})` (**lines 55-67**) instantiates a `basic_string_view` of the literal and delegates to `detail::compile_format_string<type_list<Args...>, 0, 0, …>(fmt)` (**lines 64-66**).

### Parsing Format String Fragments

The function `compile_format_string` (**lines 382-452**) walks the string character by character using constexpr recursion. It distinguishes between escaped braces, indexed arguments, named arguments, and format specifiers, delegating to specialized helpers such as:

- `parse_arg_id`
- `parse_specs`  
- `parse_replacement_field_then_tail`

Each fragment of the format string becomes a specific compile-time type:

- **`detail::text`** (**lines 27-35**): Encapsulates plain text segments
- **`detail::code_unit`** (**lines 46-54**): Represents single character units
- **`detail::field`** (**lines 71-89**): Handles simple replacement fields
- **`detail::spec_field`** (**lines 126-138**): Manages fields with format specifiers (width, precision, type)
- **`detail::runtime_named_field`** (**lines 94-121**): Supports named runtime arguments

Each struct is marked with `is_compiled_format` and provides a `constexpr format(OutputIt, const T&…)` method that writes directly to the output iterator.

### Building the Compile-Time AST

The parser stitches these fragments together using **`detail::concat`** (**lines 44-53**), a template struct that chains left-hand and right-hand nodes. Each `concat` instance provides a `format` method that forwards to its left side, then its right side. The result of `detail::compile` is a nested type hierarchy representing the entire format string as a compile-time executable structure.

## Executing Compiled Formats

The overload `fmt::format(const CompiledFormat&, const T&… args)` (**lines 76-85**) instantiates a `std::basic_string` and invokes `cf.format(std::back_inserter(s), args…)`. Because all formatting work is encoded in the compile-time type hierarchy, **no runtime parsing occurs**—only the `format` methods of the generated AST nodes are executed.

```cpp
// Zero runtime parsing overhead
auto compiled = FMT_COMPILE("Value: {:.2f}");
std::string output = fmt::format(compiled, 3.14159);

```

## C++20 User-Defined Literal Support

For C++20 compilers supporting non-type template arguments, fmt provides **`operator""_cf`** (**lines 55-60**). This user-defined literal allows compile-time parsing without macros:

```cpp
using namespace fmt::literals;

// Equivalent to FMT_COMPILE("{}")
auto fmt = "{}"_cf;
std::string s = fmt::format(fmt, 3.14);

```

Both approaches generate identical compile-time ASTs, ensuring consistent zero-overhead formatting across different C++ standards.

## Summary

- **`FMT_COMPILE(s)`** triggers compile-time parsing by marking strings with the `compiled_string` base class.
- **`is_compiled_string`** detects marked strings and routes them away from runtime parsing.
- **`compile_format_string`** recursively walks the literal at compile time to identify text, fields, and specifiers.
- **AST nodes** (`text`, `field`, `spec_field`, etc.) encode formatting logic as constexpr types with `format` methods.
- **`detail::concat`** builds the final type hierarchy representing the complete format string.
- **Execution** involves only calling the pre-compiled `format` methods, eliminating all runtime string parsing.

## Frequently Asked Questions

### What is the performance benefit of compile-time format string parsing?

Compile-time parsing eliminates the overhead of analyzing format strings at runtime. According to the fmtlib source code, when using `FMT_COMPILE`, the library skips the runtime parser entirely, executing only the `format` methods of pre-generated AST nodes. This reduces binary size for repeated formatting operations and improves execution speed by removing string traversal and state machine logic from the hot path.

### Do I need C++20 to use compile-time formatting?

No. The `FMT_COMPILE` macro works with C++14 and later by leveraging `constexpr` functions and template metaprogramming. However, C++20 provides additional convenience through the `_cf` user-defined literal, which requires support for class types as non-type template arguments. Both approaches generate equivalent compile-time representations.

### How does fmtlib handle format specifiers at compile time?

When `compile_format_string` encounters a colon within braces, it invokes `parse_specs` to analyze width, precision, alignment, and type specifiers. These specifiers become template parameters within `detail::spec_field` (**lines 126-138**), encoding the formatting requirements directly into the type system. The resulting struct stores these specifications as compile-time constants, allowing the `format` method to apply them without runtime interpretation.

### Can runtime format strings benefit from compile.h?

No. The [`compile.h`](https://github.com/fmtlib/fmt/blob/main/compile.h) infrastructure specifically targets compile-time known strings marked with `compiled_string`. Runtime strings follow the standard runtime parsing path in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h). Attempting to use runtime strings with the compile-time API will result in compilation errors, as the template machinery requires the format string content to be visible during compilation.