# YAML in 2 Minutes


``` python
from textwrap import dedent

from yaml12 import parse_yaml

first_example_text = dedent(
    """\
    title: A Modern YAML parser written in Rust
    properties: [correct, safe, fast, simple]
    score: 9.5
    categories:
      - yaml
      - python
      - example
    settings:
      note: >
        This is a folded block
        that turns line breaks
        into spaces.
      note_literal: |
        This is a literal block
        that keeps
        line breaks.
    """
)
```


Here's a short introduction to YAML for Python users. YAML is a data serialization format designed to be easy for humans to read and write.

Think of YAML as "JSON with comments and nicer multiline strings." `yaml12` parses YAML 1.2 (the modern specification that removes some of YAML 1.1's surprising eager conversions) into plain Python objects.

YAML has three building blocks: **scalars** (single values), **sequences** (ordered collections), and **mappings** (key/value pairs). JSON is a subset of YAML 1.2, so all valid JSON is also valid YAML and parses the same way.


# Why YAML 1.2?

The most visible difference between YAML 1.1 and 1.2 is how plain (unquoted) scalars get their types. YAML 1.2's recommended core schema recognizes fewer special spellings, so ordinary words such as `yes` and `on` stay strings. `yaml12` implements YAML 1.2.2.


## YAML 1.1 versus 1.2 quick reference

The YAML 1.1 column below follows its type library. The YAML 1.2 column follows the recommended core schema. Individual parsers may support a subset of these rules or offer other schemas.

| Plain YAML or feature | YAML 1.1 type library | YAML 1.2 core schema |
|----|----|----|
| `yes`, `no`, `on`, `off`, `y`, `n` | Boolean | String |
| `true`, `True`, `TRUE` (and false variants) | Boolean | Boolean |
| `010` | Octal integer `8` | Decimal integer `10` |
| `0o10` | String | Octal integer `8` |
| `0b10` | Binary integer `2` | String |
| `1:20` | Sexagesimal integer `80` | String |
| `1_000` | Decimal integer `1000` | String |
| `2026-01-07` | Timestamp | String |
| `<<` mapping key | Merge mappings | Ordinary string key |

YAML 1.2 also dropped `!!pairs`, `!!omap`, `!!set`, `!!timestamp`, and `!!binary` from its core type set. These explicit tags remain valid YAML syntax, but YAML 1.2 no longer assigns them core meanings. `yaml12` preserves them as [Yaml](../reference/Yaml.md#yaml12.Yaml) values, and handlers let application code opt into their meaning. The [advanced YAML guide](tags-anchors-and-advanced-yaml.md#core-schema-tags) shows how this works.

These changes make YAML 1.2 more conservative, not string-only. Plain `true`, `null`, and numeric forms still get typed values. For example, `10.23` is a number in both versions; quote it if it must remain a string.

Here is how `yaml12` resolves a few values that differ from YAML 1.1:


``` python
yaml_1_2 = dedent("""\
    country: NO
    enabled: on
    port: 22:22
    leading_zero: 010
    octal: 0o10
    release_date: 2026-01-07
    """)

assert parse_yaml(yaml_1_2) == {
    "country": "NO",
    "enabled": "on",
    "port": "22:22",
    "leading_zero": 10,
    "octal": 8,
    "release_date": "2026-01-07",
}
```


See the [YAML 1.2 changes](https://yaml.org/spec/1.2.2/ext/changes/) for the full specification-level list.


# A first example

``` yaml
title: A Modern YAML parser written in Rust
properties: [correct, safe, fast, simple]
score: 9.5
categories:
  - yaml
  - python
  - example
settings:
  note: >
    This is a folded block
    that turns line breaks
    into spaces.
  note_literal: |
    This is a literal block
    that keeps
    line breaks.
```

Let's parse that with `yaml12`:


``` python
doc = parse_yaml(first_example_text)

assert doc == {
    "title": "A Modern YAML parser written in Rust",
    "properties": ["correct", "safe", "fast", "simple"],
    "score": 9.5,
    "categories": ["yaml", "python", "example"],
    "settings": {
        "note": "This is a folded block that turns line breaks into spaces.\n",
        "note_literal": "This is a literal block\nthat keeps\nline breaks.\n",
    },
}
```


# Comments

Comments start with `#` and run to the end of the line. They must be separated from values by whitespace and can sit on their own line or at line ends. `yaml12` ignores them.

``` yaml
# Whole-line comment
title: example # inline comment
items: [a, b] # trailing comment
```

→ `{"title": "example", "items": ["a", "b"]}`


# Collections

There are two collection types: **sequences** and **mappings**.


## Sequences: YAML's ordered collections

A sequence is a list of items. Each item begins with `-` at the parent indent.

``` yaml
- cat
- dog
```

→ `["cat", "dog"]`

Sequences become `list`s in Python.

JSON-style arrays work too:

``` yaml
[cat, dog]
```

→ same result

Anything belonging to one of the sequence entries is indented at least one space past the dash:

``` yaml
- name: cat
  toys: [string, box]
- name: dog
  toys: [ball, bone]
```

parses to:


``` python
[
    {"name": "cat", "toys": ["string", "box"]},
    {"name": "dog", "toys": ["ball", "bone"]},
]
```


    [{'name': 'cat', 'toys': ['string', 'box']},
     {'name': 'dog', 'toys': ['ball', 'bone']}]


## Mappings: key/value pairs

A mapping is a set of `key: value` pairs at the same indent:

``` yaml
foo: 1
bar: true
```

→ `{"foo": 1, "bar": True}`

Mappings become `dict`s in Python.

A key at its indent owns anything indented more:

``` yaml
settings:
  debug: true
  max_items: 3
```

parses to `{"settings": {"debug": True, "max_items": 3}}`.

JSON-style objects work too:

``` yaml
{a: true}
```

→ `{"a": True}`


# Scalars

All nodes that are not collections are scalars; these are the leaf values of a YAML document.

Scalars can come in three forms: block, quoted, or plain.


## Block scalars

`|` starts a **literal** block that keeps newlines; `>` starts a **folded** block that joins lines with spaces (except blank/indented lines keep breaks). Block scalars always become strings.

``` yaml
|
  hello
  world
```

→ `"hello\nworld\n"`

``` yaml
>
  hello
  world
```

→ `"hello world\n"`


## Quoted scalars

Quoted scalars always become strings. Double quotes interpret escapes (`\n`, `\t`, `\\`, `\"`). Single quotes are literal and do not interpret escapes, except for `''` which is parsed as a single `'`.

``` yaml
["line\nbreak", "quote: \"here\""]
```

→ `["line\nbreak", 'quote: "here"']`

``` yaml
['line\nbreak', 'quote: ''here''']
```

→ `["line\\nbreak", "quote: 'here'"]`


## Plain (unquoted) scalars

Plain (unquoted) nodes can resolve to one of five types: string, int, float, bool, or null.

- `true` / `True` / `TRUE` and false variants -\> `True` / `False`
- `null`, `~`, or empty -\> `None`
- numbers: signed, decimal, scientific, hex (`0x`), octal (`0o`), `.inf`, `.nan` -\> `int` or `float`
- everything else stays a string (`yes`, `no`, `on`, `off` and other aliases remain strings in YAML 1.2)

``` yaml
[true, 123, 4.5e2, 0x10, .inf, yes]
```

→ `[True, 123, 450.0, 16, float("inf"), "yes"]`


# End-to-end example

``` yaml
doc:
  pets:
    - cat
    - dog
  numbers: [1, 2.5, 0x10, .inf, null]
  integers: [1, 2, 3, 0x10, null]
  flags: {enabled: true, label: on}
  literal: |
    hello
    world
  folded: >
    hello
    world
  quoted:
    - "line\nbreak"
    - 'quote: ''here'''
  plain: [yes, no]
  mixed: [won't simplify, 123, true]
```

Python result ([parse_yaml()](../reference/parse_yaml.md#yaml12.parse_yaml) with defaults):


``` python
end_to_end_text = dedent(
    """\
    doc:
      pets:
        - cat
        - dog
      numbers: [1, 2.5, 0x10, .inf, null]
      integers: [1, 2, 3, 0x10, null]
      flags: {enabled: true, label: on}
      literal: |
        hello
        world
      folded: >
        hello
        world
      quoted:
        - "line\\nbreak"
        - 'quote: ''here'''
      plain: [yes, no]
      mixed: [won't simplify, 123, true]
    """
)

parsed = parse_yaml(end_to_end_text)
assert parsed == {
    "doc": {
        "pets": ["cat", "dog"],
        "numbers": [1, 2.5, 16, float("inf"), None],
        "integers": [1, 2, 3, 16, None],
        "flags": {"enabled": True, "label": "on"},
        "literal": "hello\nworld\n",
        "folded": "hello world\n",
        "quoted": ["line\nbreak", "quote: 'here'"],
        "plain": ["yes", "no"],
        "mixed": ["won't simplify", 123, True],
    }
}
```


# Quick notes

- Indentation defines structure for collections. Sibling elements share an indent; children are indented more. YAML 1.2 forbids tabs; use spaces.
- All JSON is valid YAML.
- Sequences stay Python lists; there is no vector "simplification."
- Block scalars (`|`, `>`) always produce strings.
- Boolean words are `true`/`false` and their `True`/`TRUE` and `False`/`FALSE` variants; `null` maps to `None`.
- Numbers can be signed, scientific, hex (`0x`), octal (`0o`), `.inf`, and `.nan`.

These essentials cover most YAML you'll run into in practice. If you encounter tags, anchors, or non-string mapping keys, the advanced guide walks through those in detail.
