# How fmt::basic_appender<T> Works with fmt::format_to for Efficient Output

> Discover how fmt::basic_appender<T> enables zero-copy formatting with fmt::format_to for efficient output. Learn about direct buffer writing and reduced overhead.

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

---

**The `fmt::basic_appender<T>` iterator enables zero-copy formatting by providing a minimal output iterator interface that writes characters directly into a `detail::buffer<T>`, eliminating the overhead of standard library abstractions and temporary allocations.**

In the `fmtlib/fmt` repository, the `format_to` API achieves its high-throughput performance through a specialized output iterator that bypasses traditional C++ iterator machinery. This lightweight bridge, known as `basic_appender<T>`, allows the formatting engine to emit characters straight into user-supplied buffers without creating intermediate string objects or dragging in heavy standard library headers.

## Minimal Iterator Interface in base.h

The `basic_appender<T>` template is defined in [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h) at lines 42-60 as a thin wrapper around a `detail::buffer<T>` pointer. Unlike `std::back_insert_iterator`, it implements only the essential output iterator operations required by the C++ standard:

- `operator=` – forwards the character to `container->push_back(c)`
- `operator*` – returns the iterator itself (no-op dereference)
- `operator++` – increments the internal pointer tracking position

This minimal interface avoids the complex iterator category machinery found in the standard library, resulting in smaller binary sizes and faster compilation times.

## Zero Dependency on <iterator>

A critical optimization in the fmt library's design is the deliberate avoidance of the `<iterator>` header. By not inheriting from `std::back_insert_iterator` or including standard iterator adaptors, `basic_appender<T>` keeps compilation units lean. The implementation in [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h) relies solely on the buffer's `push_back` method, ensuring that every character write is an O(1) operation directly into contiguous memory.

## Specialized Iterator Traits

To ensure the formatting machinery treats `basic_appender<T>` as a proper output iterator without including `<iterator>`, the library provides an explicit `std::iterator_traits` specialization. Located in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) at lines 152-158, this specialization declares the `iterator_category` as `std::output_iterator_tag` and defines the appropriate value and pointer types, allowing `generic_context` and other internal templates to recognize and optimize for this iterator type.

## Memory Pre-allocation with reserve and to_pointer

Efficient output requires avoiding repeated heap allocations during formatting. The `basic_appender<T>` interface includes `reserve` and `to_pointer` helper methods defined in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) (lines 482-508). These methods allow the formatting engine to:

- **Pre-allocate capacity** – `reserve(n)` ensures the underlying buffer can accommodate `n` additional characters
- **Direct pointer access** – `to_pointer()` returns a raw pointer for bulk operations, enabling the formatter to write multiple characters through `std::memcpy` when possible

This approach prevents incremental reallocations during large formatting operations, maintaining linear time complexity regardless of output size.

## Integration with format_to

The `format_to` function constructs a `basic_appender<T>` from the target buffer and passes it to a `generic_context` instance. In [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) at lines 2221-2230, the implementation:

1. Constructs `basic_appender<char> out(buffer)`
2. Instantiates `generic_context<basic_appender<char>, char>` with the iterator
3. Drives the formatting loop, calling `*it = c` for each character

Because the iterator writes directly into the buffer's internal array via `push_back`, `format_to` achieves zero-copy output—no temporary `std::string` objects are created, and no additional memory copies occur between the formatting engine and the destination buffer.

## Practical Usage Example

The following example demonstrates direct buffer formatting using `basic_appender` through the `format_to` API:

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

int main() {
    // Create a reusable buffer that avoids repeated allocations
    fmt::memory_buffer buf;

    // Write formatted output directly into the buffer
    fmt::format_to(buf, "The answer is {}.\n", 42);

    // View the result without copying data
    std::string_view sv(buf.data(), buf.size());
    fmt::print("{}", sv);

    // Continue appending using the returned iterator
    auto it = fmt::format_to(buf, "Another {} line.\n", "formatted");
    // 'it' points just past the last written character
}

```

This pattern works for wide character variants (`basic_appender<wchar_t>`) and any custom buffer implementing the `detail::buffer<T>` interface.

## Summary

- **`basic_appender<T>`** provides a minimal output iterator interface in [`include/fmt/base.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/base.h) that writes directly to `detail::buffer<T>` instances
- **Zero standard library overhead** – the implementation avoids `<iterator>` dependencies, reducing compile times and symbol sizes
- **Direct integration** – `format_to` constructs `basic_appender` instances and passes them to `generic_context` for immediate buffer writes
- **Pre-allocation support** – `reserve` and `to_pointer` methods in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) enable bulk memory operations and prevent reallocations
- **Universal applicability** – the same efficient path supports `char`, `wchar_t`, and custom buffer types through template specialization

## Frequently Asked Questions

### What makes basic_appender more efficient than std::back_insert_iterator?

The `basic_appender<T>` avoids the heavy template machinery and header dependencies of `std::back_insert_iterator` by implementing only three required operations (`operator=`, `operator*`, `operator++`) and directly calling the buffer's `push_back` method. This eliminates virtual function indirection and unnecessary iterator category checks while preventing the inclusion of the `<iterator>` header, resulting in faster compile times and smaller binaries.

### Can I use basic_appender with my own custom buffer types?

Yes, `basic_appender<T>` works with any type satisfying the `detail::buffer<T>` interface, which requires implementing `push_back(T)`, `grow(std::size_t)`, and providing access to the underlying storage through `data()` and `size()` methods. The iterator holds a raw pointer to the buffer container, enabling direct writes without virtual dispatch overhead.

### Does format_to always construct a basic_appender internally?

When called with a `detail::buffer<T>` or `memory_buffer`, `format_to` automatically constructs a `basic_appender<T>` as the output iterator. However, `format_to` is a template function that accepts any output iterator meeting the C++ output iterator requirements. When passed standard iterators or pointers, it uses those directly rather than wrapping them in `basic_appender`.

### How does basic_appender prevent memory reallocations during formatting?

The iterator exposes `reserve(std::size_t)` and `to_pointer()` methods that allow the formatting engine to pre-allocate sufficient capacity in the underlying buffer before writing. By calculating the required output size ahead of time and reserving space via [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h) (lines 482-508), `format_to` avoids the repeated growth and copying that would occur with incremental appending, ensuring linear time complexity even for large format strings.