# How to Use `fmt::print` for Console Output in C++: A Complete Guide

> Learn to use fmt::print for efficient console output in C++ with this complete guide. Discover type-safe, high-performance formatting for stdout and FILE* streams.

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

---

**`fmt::print`** is a type-safe, high-performance formatting function that writes formatted text to `stdout` or any `FILE*` stream, implemented in [`include/fmt/core.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/core.h) as a thin wrapper around the lower-level `fmt::vprint` routine.

The {fmt} library (fmtlib/fmt) provides modern C++ formatting that eliminates the type-safety issues of `printf` and the verbosity of iostreams. **fmt::print** serves as the primary high-level API for console output, residing in [`include/fmt/core.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/core.h) around line 2906. This article examines the function's overloads, implementation details, and practical usage patterns derived directly from the source code.

## Basic Console Output to stdout

By default, **`fmt::print`** writes formatted output to standard output (`stdout`). When called without a stream argument, the function forwards to `fmt::vprint(stdout, ...)` internally, ensuring consistent behavior across platforms.

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

int main() {
    fmt::print("Hello, {}!\n", "world");          // → Hello, world!
    fmt::print("Value: {}\n", 42);
}

```

This overload provides the simplest path for quick debugging and user-facing messages while maintaining compile-time type safety.

## Writing to Custom Streams (stderr and FILE*)

For error reporting or logging to specific file descriptors, **`fmt::print`** accepts a `FILE*` as its first argument. This allows direct output to `stderr`, log files, or any valid C file stream.

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

int main() {
    fmt::print(stderr, "Error: {}\n", "something went wrong");
}

```

According to the fmtlib/fmt source, both the single-argument (stdout) and two-argument (FILE*) overloads resolve to the same underlying `vprint` implementation, guaranteeing identical formatting behavior regardless of the destination stream.

## Format String Safety and Flexibility

### Compile-Time Type Checking

The library validates format specifiers against argument types at compile time when using string literals or the **`FMT_STRING`** macro. This prevents runtime crashes from type mismatches that plague traditional `printf` calls.

The template machinery examines the format string during compilation, ensuring that `{}` placeholders match the provided arguments in type and count.

### Runtime Format Strings

When the format string is not known at compile time (e.g., user input or configuration files), wrap the string with **`fmt::runtime`** to bypass compile-time checks while maintaining safety:

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

int main() {
    std::string fmt_str = "{:04x}";
    fmt::print(fmt::runtime(fmt_str), 255);       // → 00ff
}

```

This distinction allows the library to optimize compile-time cases while supporting dynamic formatting requirements.

## Advanced Formatting Capabilities

### Colored Terminal Output

For styled console output, include [`fmt/color.h`](https://github.com/fmtlib/fmt/blob/main/fmt/color.h) and pass color specifications as the first argument. The library applies ANSI escape codes automatically:

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

int main() {
    fmt::print(fmt::emphasis::bold | fmt::fg(fmt::color::crimson),
               "Critical: {}\n", "failure");   // bold, red text
}

```

### Printing Containers and Ranges

To print C++ containers directly, include [`fmt/ranges.h`](https://github.com/fmtlib/fmt/blob/main/fmt/ranges.h). This header provides formatters for standard containers, displaying them as human-readable lists:

```cpp
#include <fmt/ranges.h>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3};
    fmt::print("{}\n", v);                       // → [1, 2, 3]
}

```

For integration with C++ iostreams rather than C `FILE*` streams, [`include/fmt/ostream.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/ostream.h) provides overloads accepting `std::ostream` references.

## How `fmt::print` Works Under the Hood

The implementation in [`include/fmt/core.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/core.h) follows a three-stage pipeline:

1. **Argument Packing** – Variadic template arguments are wrapped into an **`fmt::format_args`** pack
2. **Formatting** – **`fmt::vprint`** calls the core formatter (`fmt::detail::vformat`) which parses the format string, selects appropriate formatters for each type, and builds the output buffer
3. **Output** – The final text is emitted via standard C library functions (`fwrite`/`fputs`) on the supplied `FILE*`

This architecture separates the type-unsafe C-style output operations from the type-safe C++ interface, minimizing template bloat while maximizing performance.

## Summary

- **`fmt::print`** is defined in [`include/fmt/core.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/core.h) (around line 2906) and serves as the primary entry point for formatted console output
- The function defaults to `stdout` but accepts any `FILE*` for custom stream redirection
- Compile-time safety is enforced for literal strings; use **`fmt::runtime`** for dynamic format strings
- Terminal styling requires [`include/fmt/color.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/color.h); container printing requires [`include/fmt/ranges.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/ranges.h)
- The implementation wraps **`fmt::vprint`** with **`fmt::format_args`** packing and **`fmt::detail::vformat`** processing

## Frequently Asked Questions

### What is the difference between `fmt::print` and `fmt::format`?

**`fmt::format`** returns a `std::string` containing the formatted result, while **`fmt::print`** writes directly to `stdout` or a specified `FILE*` stream without creating intermediate string objects. Use `fmt::format` when you need to store or manipulate the result; use `fmt::print` for immediate console output.

### How do I print to stderr using `fmt::print`?

Pass `stderr` as the first argument before the format string: `fmt::print(stderr, "Error code: {}\n", code)`. This overload accepts any valid `FILE*` pointer, allowing output to log files or other streams.

### Can I use `fmt::print` with runtime format strings?

Yes, wrap the runtime string with **`fmt::runtime()`**: `fmt::print(fmt::runtime(user_input), args...)`. This disables compile-time checking for that specific format string while maintaining type safety for the arguments themselves.

### Is `fmt::print` type-safe at compile time?

Yes, when using string literals or the `FMT_STRING` macro, the library validates that format specifiers match the argument types at compile time, preventing mismatches that would cause undefined behavior in `printf`-style functions.