Minimal Three-File Configuration for fmtlib: Using base.h, format.h, and format-inl.h

The minimal three-file configuration for fmtlib consists of base.h, format.h, and format-inl.h, providing a complete header-only subset of the library with full formatting capabilities.

The {fmt} library (https://github.com/fmtlib/fmt) is typically distributed as a comprehensive formatting toolkit, but it can be reduced to just three essential headers for projects requiring a lightweight, self-contained solution. This minimal three-file configuration delivers the complete public API and core implementation without external dependencies.

The Three Core Files

The fmtlib source code is organized into modular headers, but these three specific files contain everything required for standard formatting tasks.

base.h – The Foundation

Located at include/fmt/base.h, this header defines the low-level infrastructure that the entire library builds upon. It contains compile-time feature detection macros, fundamental type utilities, and the fmt namespace scaffolding.

Key components in base.h include:

  • Version and configuration macros: FMT_VERSION, FMT_CONSTEXPR, and compiler capability detection
  • Type traits: enable_if_t, remove_cvref_t, and uint128 for internal arithmetic
  • Namespace guards: FMT_BEGIN_NAMESPACE and FMT_END_NAMESPACE wrappers that ensure proper encapsulation across different compiler environments

This file establishes the metaprogramming foundation required by the formatting engine but contains no actual formatting logic.

format.h – The Public API

The include/fmt/format.h header declares the user-facing interface, including fmt::format, fmt::format_to, fmt::print, and the basic_string_view implementation. It provides the compile-time format string checking through the format_string template and defines the format_error exception class.

Critical declarations in this header include:

  • Formatting functions: format, format_to, and print overloads
  • String view: basic_string_view implementation (with fallback support for pre-C++17 standards)
  • Context types: Forward declarations of formatter, parse_context, and format specifiers

Importantly, format.h contains only declarations and lightweight templates, ensuring fast compilation when included in translation units that do not require the heavy implementation details.

format-inl.h – The Implementation

The include/fmt/format-inl.h header provides the actual implementation of everything declared in format.h. This separation allows the heavy numeric conversion code to be compiled once and reused, mimicking the traditional single-translation-unit approach while maintaining header-only flexibility.

This file contains:

  • Core routines: do_format_decimal, format_decimal, and do_format_base2e for integer formatting
  • Floating-point conversion: The Dragonbox algorithm implementation and cache tables for high-performance decimal conversions
  • Utilities: assert_fail, locale handling functions, memory allocation helpers (detail::allocate), and report_error for throwing format_error exceptions

Because format.h includes format-inl.h at the end of the translation unit, you obtain the complete implementation without separate compilation steps.

Complete Working Example

To use the minimal three-file configuration, copy base.h, format.h, and format-inl.h into a fmt/ directory and include them in your source:

#include "fmt/base.h"
#include "fmt/format.h"
#include "fmt/format-inl.h"
#include <string>

int main() {
    // Direct output using fmt::print
    fmt::print("Hello, {}! The answer is {}.\n", "world", 42);
    
    // String formatting with precision control
    std::string s = fmt::format("Pi ≈ {:.3f}", 3.1415926535);
    // s now holds "Pi ≈ 3.142"
    
    return 0;
}

This configuration supports all standard formatting features, including positional arguments, width and precision specifiers, and type-safe formatting for built-in types.

Why This Configuration Works

The separation of concerns across these three files enables the minimal three-file configuration to function as a complete formatting library:

  1. base.h supplies the compile-time machinery and type traits required by the template-heavy API, ensuring compatibility across C++11 through C++23 standards.

  2. format.h exposes only the public interface, keeping compile times minimal for files that merely call formatting functions without needing the implementation details.

  3. format-inl.h encapsulates the heavy lifting—numeric conversions, locale handling, and memory management—allowing the compiler to optimize these routines across translation units while maintaining header-only deployment flexibility.

All other files in the fmtlib repository (such as ostream.h, printf.h, chrono.h, and xchar.h) are optional extensions built atop this foundation. They provide additional functionality for formatting standard library types, wide characters, or C-style printf compatibility, but are not required for core string formatting operations.

Summary

  • The minimal three-file configuration for fmtlib requires only base.h, format.h, and format-inl.h from the include/fmt/ directory.
  • base.h provides compiler detection, type traits, and namespace infrastructure in include/fmt/base.h.
  • format.h declares the public API including fmt::format, fmt::print, and format_string in include/fmt/format.h.
  • format-inl.h contains the Dragonbox floating-point implementation and core formatting logic in include/fmt/format-inl.h.
  • This configuration creates a header-only library subset suitable for embedded systems or vendored dependencies without CMake configuration.

Frequently Asked Questions

Can I use fmtlib with just format.h without base.h and format-inl.h?

No, format.h depends on definitions in base.h for type traits (remove_cvref_t), macros (FMT_CONSTEXPR), and namespace guards. Additionally, without format-inl.h, you will encounter linker errors for undefined implementations of do_format_decimal and Dragonbox conversion routines. All three files are required for a functional minimal configuration.

Does the three-file configuration support floating-point formatting?

Yes, format-inl.h includes the complete Dragonbox algorithm implementation and cache tables necessary for high-performance, correctly rounded floating-point decimal conversions. The format_decimal and do_format_base2e functions handle all IEEE-754 floating-point types without requiring additional headers from the full repository.

How does this minimal configuration affect compile times compared to the full library?

The three-file configuration generally improves compile times for translation units that only need the formatting API because format.h remains lightweight and declaration-focused. The heavy template instantiation and numeric conversion code reside in format-inl.h, which can be included in a single implementation file or precompiled header, while other files include only the lightweight format.h declarations.

Is the minimal three-file configuration compatible with C++11?

Yes, according to the source code in include/fmt/base.h, the library uses feature detection macros to provide fallbacks for pre-C++17 features like string_view. The basic_string_view implementation in format.h and the constexpr utilities in base.h are designed to function across C++11, C++14, C++17, and later standards, making this configuration suitable for legacy codebases.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →