# Customizing YAML Output Formatting and Indentation in yaml-cpp: A Complete Guide

> Master YAML output formatting and indentation with yaml-cpp. Learn to use Emitter and stream manipulators for precise control over your YAML generation.

- Repository: [Jesse Beder/yaml-cpp](https://github.com/jbeder/yaml-cpp)
- Tags: how-to-guide
- Published: 2026-07-11

---

**Use the `YAML::Emitter` class with global `Set*` methods for persistent changes or stream manipulators like `YAML::_Indent` for temporary, node-specific formatting.**

Customizing YAML output formatting and indentation in yaml-cpp gives you fine-grained control over how your documents are serialized. The library exposes this functionality through the `YAML::Emitter` class and its underlying `EmitterState` mechanism. By manipulating specific settings, you can adjust indentation width, line wrapping, scalar formatting, and collection styles.

## How yaml-cpp Controls Output Formatting

The emitter's behavior is driven by a set of **global** and **local** manipulators of type `EMITTER_MANIP`. These values are stored in `EmitterState` ([`src/emitterstate.h`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitterstate.h)), which tracks the current formatting configuration. When you call methods on `YAML::Emitter`, they modify this state to determine how subsequent nodes are serialized.

Global changes persist until explicitly modified, while local changes apply only to the immediate next node or block. This dual-scope system allows you to set baseline preferences while overriding them for specific structures.

## Global vs Local Configuration

### Global Format Manipulators

Global manipulators are applied through `Emitter::Set*` methods, which forward requests to `EmitterState::Set*` with a **`FmtScope::Global`** scope (see [`src/emitter.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitter.cpp), lines 73-95). These settings remain active until you change them again.

Common global methods include:
- `SetIndent(int)` — Sets spaces per indentation level
- `SetWrap(int)` — Sets column for automatic line wrapping
- `SetFloatPrecision(int)` — Controls decimal precision for floats
- `SetSeqFormat(EMITTER_MANIP)` — Sets default sequence style (`Block` or `Flow`)
- `SetMapFormat(EMITTER_MANIP)` — Sets default map style (`Block` or `Flow`)

### Local Format Manipulators

Local manipulators are injected via `operator<<` overloads defined in [`include/yaml-cpp/emitter.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emitter.h). These call `Emitter::SetLocalIndent` (or similar methods), which records values with **`FmtScope::Local`**. According to the yaml-cpp source code in [`src/emitter.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitter.cpp) (line 44), these only affect the following node or block.

When a node is emitted, `EmitterState::StartedScalar` clears any local modifications, ensuring subsequent nodes revert to the previous global configuration (see [`src/emitterstate.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitterstate.cpp), line 29).

## Indentation Mechanics in Depth

The **base indent** (`m_indent` in `EmitterState`) determines how many spaces are added for each nesting level of block collections. When a new group starts, `EmitterState::StartedGroup` captures the current indent and pushes a `Group` object onto a stack (`m_groups`). The group's `indent` field initializes from `GetIndent()` (see [`src/emitterstate.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitterstate.cpp), line 56).

The actual space insertion happens through the **`SpaceOrIndentTo`** helper (declared in [`emitter.h`](https://github.com/jbeder/yaml-cpp/blob/main/emitter.h), line 35). This function decides whether to emit a space or enough spaces to reach a target column, using the current column position and the desired indent level.

## Available Formatting Options

The yaml-cpp emitter supports extensive customization through these configuration points:

| Aspect | Method | Default |
|--------|--------|---------|
| Character set | `SetOutputCharset` | `EmitNonAscii` |
| String quoting | `SetStringFormat` | `Auto` |
| Boolean style | `SetBoolFormat`, `SetBoolCaseFormat`, `SetBoolLengthFormat` | `TrueFalseBool / LowerCase / LongBool` |
| Null representation | `SetNullFormat` | `TildeNull` |
| Integer base | `SetIntBase` | `Dec` |
| Sequence format | `SetSeqFormat` | `Block` |
| Map format | `SetMapFormat` | `Block` |
| Indentation | `SetIndent` (global) or `operator<<(_Indent)` (local) | `2` spaces |
| Pre-comment indent | `SetPreCommentIndent` | `2` |
| Post-comment indent | `SetPostCommentIndent` | `1` |
| Wrapping column | `SetWrap` | `80` |
| Float precision | `SetFloatPrecision` | `max_digits10` |
| Double precision | `SetDoublePrecision` | `max_digits10` |
| Trailing zeros | `SetShowTrailingZero` | `false` |

## Practical Code Examples

### Setting Global Indentation and Line Wrapping

```cpp
YAML::Emitter out;
out.SetIndent(4);          // use 4 spaces per level
out.SetWrap(120);          // wrap long lines at column 120

out << YAML::BeginMap;
out << YAML::Key << "title" << YAML::Value << "Demo";
out << YAML::Key << "list" << YAML::Value << YAML::BeginSeq;
out << "item1" << "item2" << "item3";
out << YAML::EndSeq << YAML::EndMap;

std::cout << out.c_str();

```

### Applying Local Indentation for Specific Blocks

```cpp
YAML::Emitter out;
out << YAML::BeginMap;
out << YAML::Key << "outer" << YAML::Value;

// Only this inner map uses an indent of 6 spaces
out << YAML::BeginMap << YAML::_Indent(6);
out << YAML::Key << "inner" << YAML::Value << "value";
out << YAML::EndMap;

out << YAML::EndMap;
std::cout << out.c_str();

```

### Controlling Scalar Precision and Trailing Zeros

```cpp
YAML::Emitter out;
out.SetFloatPrecision(5);           // 5 digits after decimal
out.SetShowTrailingZero(true);      // keep .0 on whole numbers

out << YAML::BeginMap;
out << "pi" << 3.14159;             // -> "3.14159"
out << "answer" << 42;              // -> "42.0"
out << YAML::EndMap;

```

### Switching Between Block and Flow Styles

```cpp
YAML::Emitter out;
out << YAML::BeginMap;
out << "compact" << YAML::BeginSeq << YAML::Flow << "a" << "b" << "c"
    << YAML::EndSeq;               // emits [a, b, c] on one line
out << YAML::EndMap;

```

## Key Source Files Reference

Understanding these source files helps when customizing YAML output formatting and indentation in yaml-cpp:

- **[`include/yaml-cpp/emitter.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emitter.h)** — Public API, operator overloads, and manipulator definitions
- **[`src/emitter.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitter.cpp)** — Implements global setters and local manipulator handlers
- **[`src/emitterstate.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitterstate.cpp)** — Stores formatting state and manages indentation stacks
- **[`src/indentation.h`](https://github.com/jbeder/yaml-cpp/blob/main/src/indentation.h)** — Low-level functions that write spaces and newlines based on indent levels
- **[`include/yaml-cpp/emittermanip.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emittermanip.h)** — Definitions of `EMITTER_MANIP` values (e.g., `Block`, `Flow`, `Indent`)

## Summary

- Use `YAML::Emitter` methods like `SetIndent()` and `SetWrap()` for persistent, document-wide formatting changes
- Apply local manipulators like `YAML::_Indent` via stream insertion for temporary, node-specific formatting
- Local settings automatically reset after each node due to `StartedScalar` clearing `FmtScope::Local` values
- The `EmitterState` class maintains formatting state using `m_groups` stack for nested structures
- Refer to [`emittermanip.h`](https://github.com/jbeder/yaml-cpp/blob/main/emittermanip.h) for available manipulator constants and [`emitterstate.h`](https://github.com/jbeder/yaml-cpp/blob/main/emitterstate.h) for configuration storage

## Frequently Asked Questions

### How do I change the indentation level in yaml-cpp?

Call `out.SetIndent(n)` where `n` is the number of spaces per level. This sets the global indentation used for all subsequent block collections. Alternatively, use `out << YAML::_Indent(n)` for a local change that applies only to the next node.

### What is the difference between global and local manipulators in yaml-cpp?

Global manipulators use `FmtScope::Global` and persist until explicitly changed. Local manipulators use `FmtScope::Local` and apply only to the immediate next node or block before reverting to the previous global setting. The `StartedScalar` method in `EmitterState` clears local modifications after each scalar emission.

### How can I force flow style for a specific sequence or map?

Insert `YAML::Flow` into the stream before the sequence or map: `out << YAML::BeginSeq << YAML::Flow << "a" << "b" << YAML::EndSeq`. This outputs `[a, b]` on a single line instead of using block style with newlines.

### Why are my local formatting changes not persisting across multiple nodes?

Local changes are designed to be temporary. According to the source code in [`src/emitterstate.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitterstate.cpp) (line 29), the `StartedScalar` method clears any `FmtScope::Local` modifications after each node is emitted. Use global `Set*` methods if you need changes to persist across multiple nodes.