# How to Emit YAML from C++ Objects Using yaml-cpp Emitter

> Learn how to emit YAML from C++ objects using the yaml-cpp Emitter class. Serialize C++ primitives containers and custom objects into YAML with ease.

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

---

**The `YAML::Emitter` class provides a stateful stream interface that serializes C++ primitives, containers, and custom objects into properly formatted YAML documents through `operator<<` overloads and stream manipulators.**

yaml-cpp is a widely-used C++ library for handling YAML configuration files. When you need to programmatically generate YAML output from C++ data structures, the `Emitter` class serves as the primary serialization engine, managing indentation, quoting rules, and block versus flow styles automatically.

## Core Architecture of the Emitter Class

The `Emitter` class defined in [`include/yaml-cpp/emitter.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emitter.h) acts as a token-by-token document builder. It maintains internal state to track container nesting and applies YAML syntax rules during emission.

### Construction and Stream Interface

The constructor initializes an internal `EmitterState` and wraps either an internal `std::ostringstream` or a user-provided output stream:

```cpp
Emitter();                      // Uses internal string buffer
Emitter(std::ostream& out);     // Writes directly to provided stream

```

According to the yaml-cpp source code in [`include/yaml-cpp/emitter.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emitter.h), the class exposes its output through `c_str()` when using the default internal buffer, or writes directly to the bound stream.

### Writing Primitives and Operator Overloads

The emitter provides overloaded `Write` methods for raw strings, numbers, booleans, null values, and binary data. These are wrapped by friend `operator<<` implementations that make the API feel like standard C++ streams:

```cpp
// From include/yaml-cpp/emitter.h
operator<<(Emitter&, const std::string&);
operator<<(Emitter&, int);
operator<<(Emitter&, EMITTER_MANIP);

```

When emitting `YAML::Node` objects, the `operator<<` overload defined in [`include/yaml-cpp/node/emit.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/node/emit.h) delegates to the node's internal emit implementation, allowing entire trees to be dumped in a single call.

### State Management and Syntax Validation

The implementation in [`src/emitter.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitter.cpp) handles the heavy lifting through private methods like `EmitBeginSeq`, `EmitEndMap`, and `SpaceOrIndentTo`. These maintain a stack of container contexts to enforce proper indentation and track whether the current context is flow or block style.

Error handling relies on `good()` and `GetLastError()`. If you attempt to close a sequence that was never opened, the emitter sets an error state and refuses further writes until checked.

## How to Write YAML from C++ Objects

### Basic Scalars and Sequences

Use `BeginSeq` and `EndSeq` manipulators to create block sequences. Manipulators are defined in [`include/yaml-cpp/emitterdef.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emitterdef.h):

```cpp
#include <yaml-cpp/yaml.h>
using namespace YAML;

Emitter out;
out << BeginSeq;
out << "eggs";
out << "bread";
out << "milk";
out << EndSeq;

std::cout << out.c_str() << std::endl;
// Output:
// - eggs
// - bread
// - milk

```

### Maps and Flow Style Collections

Create mappings using `Key` and `Value` manipulators. Force flow style (inline) output with the `Flow` manipulator:

```cpp
Emitter out;
out << Flow << BeginMap;
out << Key << "shape" << Value << "square";
out << Key << "color" << Value << "blue";
out << EndMap;

// Result: {shape: square, color: blue}

```

### Global Formatting Options

Control integer base representation and floating-point precision through global emitter settings. These settings affect all subsequent scalar emissions:

```cpp
Emitter out;
out << BeginSeq;
out.SetIntBase(Dec);
out << 1024;        // 1024
out.SetIntBase(Hex);
out << 1024;        // 0x400
out.SetIntBase(Oct);
out << 1024;        // 02000
out << EndSeq;

// Float precision
out.SetFloatPrecision(3);
out.SetDoublePrecision(2);
out.SetShowTrailingZero(true);

```

### Custom Types with Operator Overloading

Define a custom `operator<<` for your structs to integrate them with the emitter pipeline:

```cpp
struct Point {
    int x, y;
};

Emitter& operator<<(Emitter& out, const Point& p) {
    out << BeginMap;
    out << Key << "x" << Value << p.x;
    out << Key << "y" << Value << p.y;
    out << EndMap;
    return out;
}

// Usage
Emitter out;
out << BeginSeq;
out << Point{1, 2};
out << Point{3, 4};
out << EndSeq;
// Generates:
// - x: 1
//   y: 2
// - x: 3
//   y: 4

```

### Emitting Existing Node Trees

If you have parsed or constructed a `YAML::Node` programmatically, emit it directly without manual traversal:

```cpp
Node config = LoadFile("config.yaml");
Emitter out;
out << config;
std::cout << out.c_str();

```

The `operator<<` overload in [`include/yaml-cpp/node/emit.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/node/emit.h) handles the recursive emission of the entire node structure.

### Advanced Features: Comments, Anchors, and Tags

Add YAML comments, anchors, and custom tags using specific manipulators:

```cpp
Emitter out;
out << BeginMap;
out << Comment("Application configuration");
out << Key << "database" << Value << BeginMap;
out << Key << "host" << Value << "localhost";
out << Key << "port" << Value << 5432;
out << EndMap;
out << Key << "cache" << Value << Anchor("myCache") << BeginSeq;
out << "item1" << "item2";
out << EndSeq;
out << EndMap;

```

Fine-grained formatting controls like `SingleQuoted`, `FloatPrecision`, `UpperCase`, and `LowerCase` are available in [`include/yaml-cpp/emittermanip.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emittermanip.h) for specialized output requirements.

## Summary

- **The `YAML::Emitter` class** in [`include/yaml-cpp/emitter.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emitter.h) serves as the primary interface for writing YAML from C++ objects, operating as a stateful stream builder.
- **Stream manipulators** like `BeginSeq`, `EndMap`, `Key`, and `Value` defined in [`include/yaml-cpp/emitterdef.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emitterdef.h) control document structure and flow versus block styles.
- **Global settings** such as `SetIntBase`, `SetFloatPrecision`, and `SetShowTrailingZero` modify the formatting of subsequent scalar emissions.
- **Custom types** integrate seamlessly by overloading `operator<<(Emitter&, const T&)`, following the pattern used for standard library types.
- **Error handling** requires checking `good()` after operations, with detailed messages available through `GetLastError()` when the internal state machine in [`src/emitter.cpp`](https://github.com/jbeder/yaml-cpp/blob/main/src/emitter.cpp) detects invalid sequences.

## Frequently Asked Questions

### How do I check if yaml-cpp emission succeeded?

Call the `good()` method on your `Emitter` instance after write operations. If it returns `false`, use `GetLastError()` to retrieve a descriptive string explaining the failure, such as mismatched `EndSeq` or `EndMap` calls.

### Can I write YAML directly to a file instead of a string?

Yes. Construct the `Emitter` with an `std::ostream` reference: `Emitter out(fileStream);` where `fileStream` is an `std::ofstream`. When constructed this way, the emitter writes directly to the file rather than buffering internally, and you cannot use `c_str()` to retrieve the buffer.

### How do I force specific quoting styles on strings?

Use the `SingleQuoted` manipulator defined in [`include/yaml-cpp/emittermanip.h`](https://github.com/jbeder/yaml-cpp/blob/main/include/yaml-cpp/emittermanip.h) before emitting a string: `out << SingleQuoted << "value";`. This forces the emitter to use single quotes regardless of automatic detection. Similar manipulators exist for double quotes and literal blocks.

### What is the difference between `Flow` and `Block` styles in yaml-cpp?

`Block` style (the default) places each collection element on a new line with indentation, suitable for human readability. `Flow` style outputs collections inline using curly braces or brackets, useful for compact representations. Apply the `Flow` manipulator before `BeginMap` or `BeginSeq` to enable flow style for that specific container.