Skip to content
datahacks.dev
YAML

YAML 1.1 Versus 1.2 and Why the Difference Really Matters

The same 33 scalar values loaded by a 1.1 parser and a 1.2 parser: booleans, octal, base 60 and floats. Which libraries implement which, and how to stay safe.

5 min read
Summarize in AI
Flat illustration of two options weighed side by side, with the YAML logo.

YAML has two versions that matter in daily use, and the files do not tell you which one they are written in. The difference is not cosmetic. It decides whether NO is a country or a boolean, whether 010 is ten or eight, and whether 12:30 is a time or a number of seconds. A file that works with one tool can break with another because the tools implement different versions. This post compares the two with a table of real results and tells you how to stay out of trouble.

A short history

YAML 1.1 appeared in 2005 and became the base of the first wave of libraries: PyYAML, libyaml, Ruby's Psych, the Java SnakeYAML. YAML 1.2 followed in 2009 with the aim of making YAML a superset of JSON and cleaning up type resolution, and a revised text (1.2.2) in 2021 corrected the specification without changing the language. Despite the age of 1.2, many popular libraries still implement 1.1 behavior, by default or entirely, because changing it breaks files that exist. The result is a mixed world in which the version a file is read under depends on the program reading it.

The differences, tested

The table lists what happened to values that differ, and a few that do not.

WrittenPyYAML (1.1)ruamel.yaml (1.2)
yes, no, on, offbooleansstrings
NOFalse'NO'
y, nstringsstrings
true, True, TRUETrueTrue
010810
0o10'0o10'8
0x1F3131
1e3'1e3'1000.0
12:30750'12:30'
190:20:30685230'190:20:30'
1.101.11.1
2026-01-05a datea date
~, null, NullNoneNone

(In the full run of 33 values the two parsers disagreed on 10.) The groups behind the differences:

Booleans. 1.1 accepts a long list of spellings; 1.2 accepts true and false only. This removes the Norway problem (the Norway problem and YAML boolean surprises).

Octal numbers. In 1.1 a leading zero means octal, so 010 is 8, and a value like 0755 is 493 (file permissions, as intended), while 09 is not a valid octal and stays a string. In 1.2 octal is written 0o10, and 010 is the decimal 10. A zip code or an identifier with a leading zero is a number in both, and a wrong one.

Sexagesimal numbers. In 1.1 a colon between digits makes a base-60 number, designed for times and angles: 12:30 is 12 times 60 plus 30. That is how a port mapping 22:22 in a container file becomes the integer 1342 in a 1.1 parser, a classic source of broken Compose files. 1.2 dropped it.

Floats. 1e3 is not a float in 1.1 (it requires a dot) and is in 1.2. A tool that wrote 1e3 expecting a float gets a string from a 1.1 reader.

Merge keys and timestamps. The merge key (<<) and the timestamp type belong to the 1.1 type repository. The 1.2 core schema does not include them, yet most 1.2 libraries still support both. They are the least consistent features across libraries.

Which libraries implement which

Documented behavior, as of the versions tested or described by their projects: PyYAML implements 1.1, and so does the C library libyaml it wraps. ruamel.yaml defaults to 1.2 and can be asked for 1.1. In the test above yq, built on a Go YAML library, treated NO as a string, and kept the 1.1-style 22:22 unquoted when it appended one, which a 1.1 reader then converted to 1342. Other ecosystems are described in their own documentation: check the library you use, because the situation changes between releases, and the main libraries have long-open issues about it.

Two files can therefore be read as different data by two tools in the same pipeline. A tool written in Go may write 22:22 unquoted because, to a 1.2 reader, it is a string; a Python tool in the same repository, using PyYAML, reads it as an integer. Nothing is wrong with either tool.

Declaring the version

A YAML document may begin with a directive, %YAML 1.2, to say what it expects. In practice few files carry it and few parsers act on it consistently: some libraries use it to switch resolution rules, some ignore it, and some reject a version they do not support. It is not a reliable defense. Treat it as documentation at best.

What to do

  1. Know your parsers. List every program that reads a file, and the YAML version each implements. Test one ambiguous value in each: k: NO, k: 010, k: 12:30.

  2. Quote the ambiguous. Strings that could be booleans, numbers or times get quotes. Then the version stops mattering for them.

  3. Avoid the corner cases in unquoted values. No leading zeros on numbers you mean as numbers, no digit-colon-digit, no bare yes/no/on/off.

  4. Lint for them. yamllint's truthy rule flags the 1.1 boolean spellings, and octal-values flags values that parse as octal under either version.

  5. Validate types with a schema, so a value of the wrong type fails at load.

  6. Prefer a 1.2 parser where you control the reader. The behavior is closer to what people expect.

The cluster hub is YAML syntax you need to stop guessing at. For the individual cases, see why a number turns into something else in YAML, YAML version numbers turning into floats and YAML strings, quoting and when you need quotes. The versions are documented in the YAML 1.2.2 specification and the changes from 1.1 in its introduction. Compare outputs in the YAML to JSON tool.

When the version of YAML does not decide the behavior

The values are all quoted or plainly text. Words and sentences load the same everywhere.

The consumer reimplements parsing. Some tools use their own simplified parser and ignore both versions. Their documentation is the specification.

A schema converts the types. If a validation layer converts strings to the declared types, a number read as a string may still arrive correctly, and a boolean read as a string may not.

The data never contains ambiguous scalars. Files made only of identifiers and prose never meet the differences, and in that case the version is a non-issue until the first code is added.

Also inTooling
Share

Keep reading

Get new articles by email

We send one email when a new article is published. No spam.

Unsubscribe in one click. No spam, ever.