Skip to content
Happy Programming Guide
Start learning
Python

How to Convert a Python Dictionary to YAML

Convert a dict to YAML with PyYAML, control the formatting, handle nested data and Unicode, and load YAML back safely.

A laptop with a cup of coffee beside it

Converting a Python dictionary to YAML takes two lines with PyYAML: install it, then call yaml.dump(). The details that matter are the formatting arguments — without them you get flow style, sorted keys and escaped Unicode, none of which is what people expect — and using safe_load rather than load when reading back.

Install and convert#

Terminal
python -m pip install pyyaml
Python
import yaml

config = {
    "app": "shop",
    "debug": False,
    "port": 8080,
    "database": {"host": "localhost", "name": "shop_db"},
    "features": ["search", "cart", "checkout"],
}

print(yaml.dump(config, sort_keys=False))
Output
app: shop
debug: false
port: 8080
database:
  host: localhost
  name: shop_db
features:
- search
- cart
- checkout

The package is pyyaml but the import is yaml — a mismatch worth remembering.

The arguments worth setting#

Python
text = yaml.dump(
    config,
    sort_keys=False,          # keep your key order
    default_flow_style=False, # block style, not inline braces
    allow_unicode=True,       # real characters, not escapes
    indent=2,
    width=80,
)

What each fixes:

  • sort_keys defaults to True, which alphabetises everything and destroys any deliberate grouping.
  • default_flow_style controls whether nested data is written inline. Modern PyYAML defaults to block style, but being explicit costs nothing.
  • allow_unicode is the one people miss. Without it, accented characters come out as escape sequences.
Python
data = {"city": "M\u00fcnchen", "note": "caf\u00e9"}

print(yaml.dump(data))                     # escaped, hard to read
print(yaml.dump(data, allow_unicode=True)) # city: München

Indenting lists properly#

PyYAML puts list dashes at the parent’s indent level by default. Many people prefer them indented:

Python
class IndentedDumper(yaml.SafeDumper):
    def increase_indent(self, flow=False, indentless=False):
        return super().increase_indent(flow, False)


print(yaml.dump(config, Dumper=IndentedDumper, sort_keys=False))
Output
features:
  - search
  - cart
  - checkout

Both forms are valid YAML and parse identically. This is purely about how it reads.

Writing to a file#

Python
from pathlib import Path

with open("config.yaml", "w", encoding="utf-8") as f:
    yaml.dump(config, f, sort_keys=False, allow_unicode=True)

# or via pathlib
Path("config.yaml").write_text(
    yaml.dump(config, sort_keys=False, allow_unicode=True),
    encoding="utf-8",
)

Always specify encoding="utf-8". Without it, the platform default is used, and on some Windows configurations that cannot represent the characters allow_unicode just preserved.

Reading it back#

Python
with open("config.yaml", encoding="utf-8") as f:
    loaded = yaml.safe_load(f)

print(loaded["database"]["host"])

For a file containing several documents separated by ---:

Python
for document in yaml.safe_load_all(text):
    print(document)

Types that need attention#

Python
import datetime

data = {
    "when": datetime.date(2026, 9, 6),      # written as a native YAML date
    "pair": (1, 2),                          # tuple - needs care
    "unique": {1, 2, 3},                     # set - needs care
    "nothing": None,                         # written as null
}

print(yaml.dump(data, default_flow_style=False))

Dates and None are handled natively. Tuples and sets are written using PyYAML-specific tags that other YAML parsers will not understand, and safe_load will refuse to read back. Convert them first:

Python
def yaml_ready(obj):
    if isinstance(obj, dict):
        return {str(k): yaml_ready(v) for k, v in obj.items()}
    if isinstance(obj, (list, tuple, set)):
        return [yaml_ready(v) for v in obj]
    return obj


print(yaml.dump(yaml_ready(data), sort_keys=False))

Note that a tuple becomes a list on the way out, so it will not come back as a tuple. YAML has no tuple concept, and that is fine for configuration.

Custom objects#

Python
from dataclasses import dataclass, asdict


@dataclass
class Server:
    host: str
    port: int


servers = [Server("a.example.com", 80), Server("b.example.com", 8080)]

print(yaml.dump([asdict(s) for s in servers], sort_keys=False))

Converting to plain dictionaries first keeps the output portable. PyYAML can serialise arbitrary objects with tags, but the result is only readable by PyYAML, which defeats most of the reason for choosing YAML.

Multi-line strings#

Python
data = {"description": "First line\nSecond line\nThird line"}

print(yaml.dump(data, default_style="|"))
Output
description: |-
  First line
  Second line
  Third line

The pipe character introduces a literal block, which preserves the line breaks. It is much more readable than a single long line full of escape sequences.

YAML or JSON?#

YAML JSON
Comments Yes No
Written by hand Comfortable Awkward
In the standard library No Yes
Whitespace sensitive Yes No
Best for Configuration Data interchange

The short version: YAML for files people edit, JSON for data programs exchange.

Questions people ask#

Is YAML part of the standard library?

No. PyYAML is a third-party package. JSON and tomllib are built in; YAML is not.

Why is my key order alphabetical?

sort_keys defaults to True. Pass sort_keys=False to keep the order of your dictionary.

What about ruamel.yaml?

It supports newer YAML versions and, importantly, preserves comments and formatting when you load and re-save a file. Worth using if you are editing files people also maintain by hand.

How do I add comments to generated YAML?

PyYAML cannot. Either write the header yourself before dumping, or use ruamel.yaml, which supports comments properly.

Where to go next#

The standard library modules worth knowingRead next

Keep reading

Python

The Python Standard Library

The modules that come with Python and are worth knowing: pathlib, json, csv, datetime, collections, itertools, re, argparse and more, each with…

4 min read

Keep going — pick your next guide

The fastest way to improve is to read one guide, then build the thing it describes. Start with the basics, or jump straight to a project.

Ask a question or share what worked

Your email address will not be published. Required fields are marked *