Here’s a short introduction to YAML for R users. YAML is a data serialization format designed to be easily human readable.
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 R
objects.
YAML has three building blocks: scalars (single values), sequences (ordered collection of items), and mappings (key/value pairs with unique keys). JSON is a subset of YAML 1.2, so all valid JSON is also valid YAML and parses the same way.
title: A Modern YAML parser written in Rust
properties: [correct, safe, fast, simple]
score: 9.5
categories:
- yaml
- r
- example
settings:
simplify: true
note: >
This is a folded block
that turns line breaks
into spaces.
note_literal: |
This is a literal block
that keeps
line breaks.str(parse_yaml(first_example))
#> List of 5
#> $ title : chr "A Modern YAML parser written in Rust"
#> $ properties: chr [1:4] "correct" "safe" "fast" "simple"
#> $ score : num 9.5
#> $ categories: chr [1:3] "yaml" "r" "example"
#> $ settings :List of 3
#> ..$ simplify : logi TRUE
#> ..$ note : chr "This is a folded block that turns line breaks into spaces.\n"
#> ..$ note_literal: chr "This is a literal block\nthat keeps\nline breaks.\n"There are two “collection” types: Sequences and Mappings.
A sequence is a list of items. Each item begins with -
at the parent indent.
→ c("cat", "dog") (or list("cat", "dog")
when simplify = FALSE)
JSON-style arrays work too:
→ same result
Anything belonging to one of the sequence entries is indented at least one space past the dash:
↓
A mapping is a set of key: value pairs at the same
indent:
→ list(foo = 1L, bar = TRUE)
A key at its indent owns anything indented more:
→
list(settings = list(simplify = TRUE, max_items = 3L))
JSON-style objects also work:
→ list(a = TRUE)
Mappings become named lists in R.
All nodes that are not collections are Scalars; these are the leaf nodes of a YAML document.
Scalars can be provided in three forms: block, quoted, or plain.
Like block scalars, quoted scalars always resolve to strings. Double
quotes interpret escapes (\n, \t,
\\, \"). Single quotes are literal and do not
interpret escapes, except for '' which is parsed as a
single '.
→ c("line\nbreak", 'quote: "here"')
→ c("line\\nbreak", "quote: 'here'")
If a node is not a sequence, mapping, block scalar, or quoted scalar, it is a plain scalar.
Plain nodes can resolve to one of five types: string, int, float, bool, or null.
YAML 1.2 uses simple rules to then infer the type of a plain node:
true / false and their
True/TRUE and
False/FALSE variants → TRUE /
FALSEnull, ~, or empty → NULL0x), octal
(0o), .inf, .nan →
numeric() or integer()yes, no,
on, off and other aliases remain strings in
YAML 1.2)→ list(TRUE, 123L, 450, 16L, Inf, "yes")
If a sequence is homogeneous and simplify = TRUE, nulls
become the appropriate NA_* values.
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]R result (parse_yaml() with defaults):
list(
doc = list(
pets = c("cat", "dog"),
numbers = c(1, 2.5, 16, Inf, NA_real_),
integers = c(1L, 2L, 3L, 16L, NA_integer_),
flags = list(enabled = TRUE, label = "on"),
literal = "hello\nworld\n",
folded = "hello world\n",
quoted = c("line\nbreak", "quote: 'here'"),
plain = c("yes", "no"),
mixed = list("won't simplify", 123L, TRUE)
)
)For most R users, the main 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. R’s yaml package implements
a YAML 1.1 parser and emitter, while yaml12 implements YAML
1.2.2.
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. Those explicit tags remain valid YAML syntax,
but YAML 1.2 no longer assigns them core meanings. yaml12
preserves them as unhandled tags, and handlers let application code opt
into their meaning. The advanced
YAML article 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:
yaml_1_2 <- "
country: NO
enabled: on
port: 22:22
leading_zero: 010
octal: 0o10
release_date: 2026-01-07
"
str(parse_yaml(yaml_1_2))
#> List of 6
#> $ country : chr "NO"
#> $ enabled : chr "on"
#> $ port : chr "22:22"
#> $ leading_zero: int 10
#> $ octal : int 8
#> $ release_date: chr "2026-01-07"See the YAML 1.2
changes for the full specification-level list and the yaml12
release post for more background.
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.
Homogeneous sequences simplify to vectors unless
simplify = FALSE.
Block scalars (|, >) always produce
strings.
Boolean words are true/false and their
True/TRUE and
False/FALSE variants.
null maps to NULL (or NA
inside simplified vectors).
These essentials cover most YAML you’ll run into in practice. If you encounter YAML tags or non-string mapping keys, check out the “Advanced YAML” vignette.
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; they are ignored by the parser.→
list(title = "example", items = c("a", "b"))