By Docify

YAML 1.2 Core vs 1.1: Norway, Comments, JSON

• 6 min read

YAML 1.2 Core (the schema js-yaml 5 load uses here) treats yes and NO as strings. YAML 1.1’s boolean type would turn NO into false — the Norway problem (ISO 3166-1 alpha-2). Comments never survive load. This comparison is not a converter. Convert on /yaml-to-json/.

The same YAML bytes can mean different native values depending on the schema. The live YAML converter parses one document with js-yaml 5 CORE_SCHEMA (YAML 1.2 Core, spec §10.3). The sample fills name: Docify, a tools sequence of json and yaml, count: 2, and enabled: true. Convert then writes the matching 2-space JSON {"name":"Docify","tools":["json","yaml"],"count":2,"enabled":true}. This page names what that schema keeps as text, what YAML 1.1 used to coerce, and what a JSON round trip must drop — comments first.

Implicit types: 1.2 Core vs 1.1

Booleans: Norway is a string in Core

YAML 1.2.0 (2009-07-21) made Core the recommended default. Spec 10.3.2 resolves only true / True / TRUE and false / False / FALSE. YAML 1.1 !!bool (2005-01-18) also accepted yes / no / on / off and the single letters y / n in a fixed list of capitalizations. Norway’s country code NO is on that list, so a 1.1 loader turns it into false. The live converter leaves it as the two characters N and O. nO was never a 1.1 boolean. The live load turns enabled: True into {"enabled":true} and enabled: FALSE into {"enabled":false}. RFC 8259 / ECMA-404 allow only lowercase true and false, so JSON.parse("True") throws. Quoted "True" stays a string. Mixed-case TruE stays a string.

True → true · FALSE → false · "True" stays "True" · NO stays "NO"

Integers: 0o octal, no sexagesimal

Core integers are decimal [-+]?[0-9]+, octal 0o[0-7]+, and hex 0x[0-9a-fA-F]+. A leading zero is still decimal: 010 is 10 and 0777 is 777. YAML 1.1 !!int treated a leading 0 as octal (010 → 8, 0777 → 511), allowed 0b binary and _ separators, and parsed sexagesimal 1:30:00 as 5400. Core keeps that colon form as a string. An underscore form such as 1_000 stays a string; write 1000. YAML 1.1 !!int ignored _ (+685_230 → 685230). 1.2.2 (2021-10-01) did not change these rules.

0o10 → 8 · 010 → 10 · 1_000 stays "1_000" · 1:30:00 stays "1:30:00"

.5 and 1. are Core floats

YAML 1.2.2 §10.3.2 matches plain floats as [-+]? ( \. [0-9]+ | [0-9]+ ( \. [0-9]* )? ) ( [eE] [-+]? [0-9]+ )?. The spec example lists 0., .5, +12e03, and -2E+05. The live load turns value: .5 into {"value":0.5} and value: 1. into {"value":1}. value: 1e2 is {"value":100}. RFC 8259 / ECMA-404 reject those incomplete-looking decimals; write 0.5 or 1.0. Quoted ".5" stays a string. YAML 1.1 !!float (yaml.org/type/float.html) required a decimal point, ignored _ (685_230.15), and parsed sexagesimal 190:20:30.15. Core keeps those output forms as strings. This is not the .inf → JSON null stringify case.

.5 → 0.5 · 1. → 1 · 1e2 → 100 · 685_230.15 stays "685_230.15"

Empty values are null, not empty strings

YAML 1.2.2 §10.3.2 resolves null / Null / NULL / ~ and an empty scalar as !!null. Spec §7.2 says omitted node content is commonly null. The live load turns value: ~, value: null, and value: (nothing after the colon) into {"value":null}. Write value: "" for {"value":""}. Quoted "null" and "~" stay strings. none and nil stay strings. An empty input stream throws “expected a document”. YAML 1.1 !!null used the same forms. This is not the .inf → JSON null stringify case.

value: ~ → { "value": null } · value: "" → { "value": "" }

Dates stay strings; << is a key

YAML 1.2.2 §10.3.2 has no timestamp regex, so the live load keeps a date-only value such as 2026-08-20 as the hyphenated string. YAML 1.1 !!timestamp (yaml.org/type/timestamp.html) resolved that form as 00:00:00Z; JSON.stringify of that Date would write "2026-08-20T00:00:00.000Z". An ISO form such as 2001-12-15T02:59:43.1Z also stays a string here. An explicit !!timestamp tag throws “unknown scalar tag !<tag:yaml.org,2002:timestamp>”. Quoted "2026-08-20" stays a string. The 1.1 merge key << and value key = were removed in 1.2; here << is just a mapping key. Duplicate keys throw. A leading --- on one document converts. A second document after --- throws “expected a single document in the stream, but found more”. Empty input throws “expected a document”.

date: 2026-08-20 → { "date": "2026-08-20" } · YAML 1.1 Date → { "date": "2026-08-20T00:00:00.000Z" }

--- starts another document

YAML 1.2.2 §9.1 / §9.2 allow several documents in one stream. --- is c-directives-end, not a syntax error. The live load accepts one document. A trailing --- after a finished document starts an empty second document and throws too. A document-end ... after one document is fine. --- inside a quoted string is content. This is not loadAll.

--- then a: 1 → { "a": 1 } · a: 1 then --- then b: 2 → throw

Tabs are not block indentation

YAML 1.2.2 §6.1 says block indentation is spaces only (s-indent is s-space). The live load throws “tab characters must not be used in indentation” when a nested key is tab-indented. Two spaces convert. A tab inside a scalar is content and is kept. A tab between flow tokens is separation (spec 6.2). dump writes 2-space indent, never tabs.

tab before b: 1 → throw · two spaces → { "a": { "b": 1 } }

Literal | keeps newlines; > folds them

YAML 1.2.2 §8.1.2 literal | keeps line breaks. §8.1.1.2 clip (default) keeps the final line break and drops trailing empty lines. The live load turns note: | with indented hello / world into {"note":"hello\nworld\n"}. |- is strip: {"note":"hello\nworld"}. |+ is keep and matches clip unless extra blank lines follow (spec example 8.5). §8.1.3 folded > turns those same lines into {"note":"hello world\n"}. >- is {"note":"hello world"}. Quoted "hello\nworld" is already that string. A | block whose content is True stays "True\n", not a boolean — Core bool matching is for plain scalars. dump may rewrite > as | or a plain scalar. This is presentation, not a YAML 1.1 vs 1.2 type change.

| hello/world → {"note":"hello\nworld\n"} · |- → no final \n · > → {"note":"hello world\n"}

What a JSON round trip cannot keep

Integer and boolean keys become JSON strings

YAML 1.2.2 §3.2.1.1 says mapping keys may be arbitrary nodes. RFC 8259 §4 / ECMA-404 require every JSON object member name to be a string. There is no numeric-key production. js-yaml 5 load with CORE_SCHEMA builds a JavaScript object, so own keys are already strings, then JSON.stringify writes those names. 1: one becomes {"1":"one"}. true: yes becomes {"true":"yes"} — the value yes stays a string. Quoted "1": one is already that string name. 010: padded becomes {"10":"padded"} because the key is the Core integer 10, then ToString. ~: missing becomes {"null":"missing"}. A sequence or mapping key throws “object-based map does not support complex keys”. 1: and "1": in the same mapping throw as a duplicate key. JSON.parse('{1:"one"}') throws. This is not a YAML 1.1 vs 1.2 type change.

1: one → {"1":"one"} · true: yes → {"true":"yes"} · 010: padded → {"10":"padded"}

Merge << is a key; aliases become copies

YAML 1.2.2 §3.2.2.2 / §6.9.2 / §7.1 keep anchors (&) and aliases (*). An alias composes to the anchored node. js-yaml 5 load with CORE_SCHEMA expands that node, then JSON.stringify writes two copies because JSON has no aliases. item: &id with name: Docify and copy: *id becomes {"item":{"name":"Docify"},"copy":{"name":"Docify"}}. The YAML 1.1 merge key << (yaml.org/type/merge.html) inserted keys from one or more mappings. YAML 1.2.0 (2009-07-21) removed the merge << and value = special keys. CORE_SCHEMA does not enable !!merge, so << is an ordinary string name. base: &base with host: localhost and port: 80, then app: / <<: *base / name: docify, becomes {"base":{"host":"localhost","port":80},"app":{"<<":{"host":"localhost","port":80},"name":"docify"}} — the alias expanded into the << value; host and port were not inserted beside name. <<: [*a, *b] becomes a JSON array under "<<". Quoted "<<": extra is already that string name. =: stays "=". An explicit !!merge tag throws “unknown scalar tag !<tag:yaml.org,2002:merge>”. dump with noRefs inlines copies and does not rewrite <<. This is not Kubernetes merge.

<<: *base → {"<<":{"host":"localhost","port":80}} · &id / *id → two copies · !!merge → throw

!!str 010 stays a string

YAML 1.2.2 §6.8.2.1 says !! is the secondary tag handle. The default prefix is tag:yaml.org,2002:, so !!str is tag:yaml.org,2002:str. §6.9.1 says an explicit tag names the type. Core §10.3.1 uses the same tags as the JSON schema: str, seq, map, null, bool, int, and float. An explicit tag skips the plain-scalar regex in §10.3.2. js-yaml 5 load with CORE_SCHEMA turns value: !!str 010 into {"value":"010"}. value: !!int 010 is still {"value":10} — Core decimal, not YAML 1.1 octal. value: !!str true is {"value":"true"}. value: !!bool true is {"value":true}. value: !!bool yes throws “cannot resolve a node with !<tag:yaml.org,2002:bool> explicit tag” because Core bool is only those six spellings. value: ! 010 (non-specific !) also becomes {"value":"010"} — §10.3.2 resolves ! to str, seq, or map by kind. Quoted "010" is already that string without a tag. !!binary, !!timestamp, !!merge, !!set, and !!omap throw “unknown scalar tag” — YAML 1.2 dropped those 1.1 types. This is not a YAML 1.1 schema.

!!str 010 → {"value":"010"} · !!int 010 → {"value":10} · !!bool yes → throw

Integers past 2^53 − 1 round

YAML 1.2.2 §10.2.1.3 (Integer) represents arbitrary-sized mathematical integers and says a processor should bind them to a native integer type if possible. An overflow may be rejected, truncated, or otherwise round-tripped; 32-bit integers should be safe. js-yaml 5 load with CORE_SCHEMA uses parseInt, which returns a JavaScript Number (IEEE-754 binary64; ECMA-262). Exact integers end at Number.MAX_SAFE_INTEGER, 9007199254740991 (2^53 − 1). value: 9007199254740993 becomes {"value":9007199254740992}. value: !!int 9007199254740993 and hex 0x20000000000001 do the same. JSON.stringify then writes that even value. RFC 8259 §6 expects JSON number interoperability in that binary64 range. Quoted "9007199254740993" stays the exact string. This is the host Number, not a YAML 1.1 vs 1.2 type change. The live converter does not parse integers as BigInt.

9007199254740993 → {"value":9007199254740992} · quoted string stays exact

JSON "010" dumps as '010'

JSON → YAML calls JSON.parse, then js-yaml 5 dump with CORE_SCHEMA. dump's default quoteStyle is single; the live converter does not set forceQuotes. YAML 1.2.2 §10.3.2 applies Core tag resolution to plain scalars. An unquoted 010 would load as the integer 10. §7.3.2 (Single-Quoted Style) writes a string that skips that implicit typing. dump therefore quotes a JSON string when a plain scalar would resolve as a Core int, bool, null, or float. {"value":"010"} becomes value: '010'. {"value":"true"} becomes value: 'true'. {"value":"null"} becomes value: 'null'. {"value":"yes"} stays value: yes — Core keeps yes as a string, so dump does not quote it. {"value":"2026-08-20"} stays unquoted. {"1":"one"} becomes '1': one. A later YAML → JSON load keeps those quoted strings. Unquoted value: 010 still becomes {"value":10}. This is presentation, not a YAML 1.1 vs 1.2 type change.

{"value":"010"} → value: '010' · {"value":"yes"} → value: yes

Comments are presentation, not data

Spec 3.2.3.3 puts comments in the presentation stream. They are not nodes. After load, the in-memory value is a plain object or array. dump writes CORE_SCHEMA YAML with 2-space indent, unlimited line width, and noRefs: true so a shared object is inlined twice instead of &anchor / *alias. Quote style and key order are not a formatter guarantee. Click Convert to process.

name: Docify # kept? → { "name": "Docify" }

.inf and .nan become JSON null

Core still types .inf and .nan as floats. In the browser those are Infinity and NaN. JSON.stringify (ECMA-262) serializes a non-finite Number as null. JSON → YAML then uses JSON.parse, so a later dump sees JSON null and writes YAML null, not .inf. Trailing commas and single-quoted JSON are rejected on that path. This is not a YAML 1.1 boolean change.

Convert one YAML 1.2 Core document

yes / NO stay strings. Comments do not. Nothing is uploaded.

Use YAML to JSON →

FAQ

What changed from YAML 1.1 to 1.2?
YAML 1.2 Core still types true/false, null, and numbers. It no longer treats yes/no/on/off as booleans (the Norway problem) and no longer treats a leading 0 as octal — 010 is decimal 10; write 0o10 for octal 8. JSON is valid YAML 1.2. Docify parses with js-yaml 5 CORE_SCHEMA, not YAML 1.1.
Is yes still a boolean?
In YAML 1.2 Core schema, yes is a string. Only true/false are booleans. Many parsers still use 1.1 rules.
Which version should I use?
Use YAML 1.2 for new projects. It is more predictable and JSON-compatible.
Does this tool upload my data?
No. All parsing runs in your browser using JavaScript. Nothing is sent to a server.

Related