YAML Format & Validate
Validate, lint (yamllint rules), format and explore YAML 1.2, and convert it to JSON. Comments are kept when formatting. Runs in your browser.
Where your data goes
| Using this page | Using the API, MCP or A2A | |
|---|---|---|
| Where it runs | In your browser. Linting, formatting and conversion all run in JavaScript on this page (the eemeli/yaml library plus this site's strict JSON parser), so nothing you paste is sent anywhere. | In a Cloudflare Pages Function at the Cloudflare data centre nearest the caller. |
| What leaves your device | Nothing you enter. After the page and its scripts load, no request
carries your input. The browser enforces this: the page's Content-Security-Policy
sets connect-src 'none' and form-action 'none', which
block fetch, XHR, WebSocket, EventSource, beacons and form posts.
| The server receives the JSON text, processes it in memory inside the request, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. The server makes no network requests. For confidential documents use the page, which does the same work in your browser and sends nothing. The server receives the YAML text, processes it in memory inside the request, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. The server makes no network requests. For confidential documents use the page, which does the same work in your browser and sends nothing. The server receives the YAML text and the options, processes them in memory inside the request, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. The server makes no network requests. For confidential documents use the page, which does the same work in your browser and sends nothing. |
| Stored | Nothing leaves the page. No cookies, analytics or third-party scripts; the browser keeps only your View → Inline config choice. | Your inputs and results: never. What is stored is your client record (client ID, a SHA-256 hash of your secret, expiry, and the profile you registered with) and one metadata row per call: operation, time, transport, status, error code, duration, request and response sizes, and country. |
| Logged | Nothing (no requests are made). | Only the per-call metadata above, attributed to your client ID. Never parameters, bodies, results, or credentials. Cloudflare, as the host, also processes request metadata (IP address, full URL including the query string, headers) under its own policies, so put inputs in POST bodies. |
| Access | Open to anyone. | Requires a client ID and secret (how to get one). HTTPS only; TLS terminates at Cloudflare. |
Details and how to verify this yourself: Security & privacy.
User guide
The YAML studio checks, formats and converts YAML in one place. Paste or type a document into Input: it is checked as you type. Choose what to look at from the View menu; the badge in the status line names the current view, and the Problems button next to it counts the findings.
| View | What it shows |
|---|---|
| Input | Your YAML, editable, with line numbers. |
| Formatted | The document re-written to a consistent style, with your comments kept. Use as input copies it back into Input. Empty when the YAML is invalid. |
| Tree | The data as a collapsible tree. Each entry shows its type (mapping, sequence, string, integer, float, boolean, null) and its path. |
| JSON | The same data converted to JSON (see YAML → JSON below). |
| Problems | Every finding, in document order, with its rule, severity, line and column. Click one to jump to that spot in Input. |
Menus. The studio works like a desktop window. Its menu bar has File (open, load the sample, download, clear), Edit (format, copy), View (switch views, show the options inline, full screen), Settings (Options… opens the options in an overlay) and Help (jumps to these sections, and lists the keyboard shortcuts). The full-screen icon sits at the right of the same row: two arrows pointing out make the studio fill the window, and arrows pointing in (or Esc) bring it back.
Edit → Format (or Ctrl+Enter) shows the formatted document on the Formatted view; your Input is never changed unless you press Use as input there. The JSON view always shows the converted data, updating as you type. The Formatted and JSON views each have their own Copy and Download buttons. The File menu has Open file… (a .yaml or .yml file), Load sample (a short file with a few findings), Download input and Clear input.
Settings → Options…. These settings change the findings and the formatted output together:
- Indent: 2 or 4 spaces per level.
- Sequences: whether lists under a key are indented. Indented puts
- itemone level in underkey:. Flush puts- itemin the key’s column. Consistent (the default) accepts either, as long as the whole file does the same; the first list decides. - Max line length: 120 by default, or off. yamllint’s default is 80, which most Kubernetes manifests and CI files exceed, so the default here is 120.
- Document start: Ignore (default), Require
---before every document, or Forbid it on the first document. - Quote style: Any (default), Single or Double.
Reading the findings. An error means the YAML is unusable: it does not parse, a mapping has the same key twice, or an alias refers to an anchor that does not exist. Formatted, Tree and JSON stay empty until errors are fixed. A warning is a style or portability problem, and info is a note. The rules and their IDs match yamllint, so a finding here is one yamllint would report with the same settings. The exception is that some yamllint errors are warnings here (see the rules table).
Why YAML 1.1 matters. YAML has two versions in wide use. YAML 1.2 (2009) is what this page and the eemeli/yaml library follow. YAML 1.1 is still what PyYAML, Ruby’s Psych, SnakeYAML and Go’s yaml.v2 implement, so Ansible, many CI systems and older Kubernetes tooling read your file as 1.1. The same plain text means different things:
| You write | YAML 1.2 (this page) | YAML 1.1 parsers |
|---|---|---|
country: no | the string "no" | false (the “Norway problem”) |
enabled: yes, on, off, y, n | strings | booleans |
mode: 0755 | the integer 755 | octal 0755 = 493 |
mode: 0o755 | octal 0o755 = 493 | the string "0o755" |
time: 1:20 | the string "1:20" | 80 (base 60) |
size: 1_000 | the string "1_000" | 1000 |
date: 2024-01-01 | the string "2024-01-01" | a date |
The truthy and octal-values rules flag the first rows. YAML → JSON warns about every value in the left column whose meaning differs, and JSON → YAML double-quotes any string that either version would read as something else.
Converting.
- YAML → JSON takes the first document, or all of them (All documents gives a JSON array). Merge keys (
<<: *defaults, common in Docker Compose and CI files) are applied by default; turn them off to keep<<as an ordinary key. Custom tags such as CloudFormation’s!Refand!GetAtt, or YAML 1.1’s!!binary, have no JSON equivalent, so by default they are an error. Drop tags keeps the value and discards the tag; Wrap tags keeps both, as{"!Ref": "MyBucket"}. - JSON → YAML is the reverse conversion. On this site it is the As YAML view of the JSON studio. The result is block-style YAML 1.2 that means the same under YAML 1.1.
Specification
Library. eemeli/yaml 2.9, configured for YAML 1.2 with the core schema, strict mode, and unique keys. The linter reads the library’s concrete syntax tree, which holds every token with its position. It never matches regular expressions against raw lines, so a # inside a string or a blank line inside a block scalar is never mistaken for a comment or a style problem.
YAML 1.2 is pinned. A %YAML 1.1 directive does not switch rules; YAML → JSON warns about it. Plain scalars resolve as in the 1.2 core schema:
| Type | Forms |
|---|---|
| null | null, Null, NULL, ~, or nothing |
| boolean | true, True, TRUE, false, False, FALSE |
| integer | decimal (-17, 0755 is 755), octal 0o17, hexadecimal 0x1F |
| float | 1.5, .5, 1e3, -1.5E-3; .inf, -.inf, .nan (rejected by YAML → JSON, see below) |
| string | everything else, including yes, no, on, off, 1_000, 0b101, 1:20 and dates |
Lint rules
Rule IDs and default behaviour follow yamllint’s default configuration. yamllint reports most style rules at error level; here they are warnings, because they do not change what the document means, and an error is kept for YAML that cannot be used. Positions are 1-based lines and columns counted in Unicode code points, plus a 0-based UTF-16 offset; most findings also give an end position.
| ID | Level | What it checks | Format fixes it | yamllint |
|---|---|---|---|---|
syntax | error | The text parses. The message is the library’s, at the exact position (unclosed quotes and brackets, bad indentation, tabs used for indentation, a nested mapping on one line, and so on); at most 50 are listed. A core tag that does not fit its value, such as !!int abc, is a warning. | no | syntax errors |
key-duplicates | error | No key appears twice in one mapping. << merge keys may repeat. | no | key-duplicates |
anchors | error | Every alias *name has an anchor &name before it in the same document (error). An anchor declared again is a warning, and an anchor that no alias uses is info. | no | anchors (with forbid-duplicated-anchors and forbid-unused-anchors on) |
braces | warning | No spaces just inside {}: {a: 1}, and {} when empty. | yes | braces |
brackets | warning | No spaces just inside []: [1, 2], and [] when empty. | yes | brackets |
colons | warning | No space before : and one space after it. *alias : value is allowed, because the space is required there. | yes | colons |
commas | warning | No space before , and exactly one after it, unless the line ends. | yes | commas |
comments | warning | A comment starts with # (shebangs #! on line 1, ### banners and a bare # are fine), and an inline comment is at least 2 spaces after the content. | spacing before the # only | comments |
comments-indentation | warning | A comment on its own line is indented like the next line of content, or like the previous one when it closes a block. | yes, except a comment just before the closing bracket of a multi-line flow collection | comments-indentation |
document-start | warning | Off unless chosen. Require: every document starts with ---. Forbid: the first document has no ---. Later --- markers separate documents, a document with % directives needs its marker, and so does an empty first document. | yes | document-start |
empty-lines | warning | At most 2 blank lines in a row, none at the start of the file and none at the end. Lines inside block or multi-line scalars are content and are not counted. | yes (Format keeps at most 1) | empty-lines |
empty-values | info | key: with nothing after it, in block or flow mappings. The value is null, which is often a mistake; write null or ~ to say so. | no | empty-values (off by default in yamllint) |
hyphens | warning | Exactly one space after the - of a list item. | yes | hyphens |
indentation | warning | The root starts in column 1. Each nested block is indented by the chosen width relative to its parent’s content. Lists under a key follow the Sequences option. A mapping that starts on the same line as its - is measured from its first key. Block scalar contents are not checked. | yes | indentation (check-multi-line-strings: false) |
line-length | warning | No line is longer than the limit (120 by default; off on request). A line whose content is a single word, such as a long URL after - or # , is allowed. | no | line-length (allow-non-breakable-words) |
new-line-at-end-of-file | warning | The text ends with a line break. | yes | new-line-at-end-of-file |
new-lines | warning | Line breaks are LF. CRLF, CR, or a mix, are reported once, at the first one. | yes | new-lines (type: unix) |
octal-values | warning | No plain 0755 (decimal 755 in 1.2, octal 493 in 1.1) or 0o755 (octal in 1.2, a string in 1.1). Quoted or tagged values are fine. | no | octal-values (off by default in yamllint) |
quoted-strings | warning | Off unless chosen. Single: values in double quotes that could use single quotes. Double: values in single quotes. Keys are not checked. | yes | quoted-strings (quote-type) |
trailing-spaces | warning | No spaces or tabs at the end of a line. | yes, except inside block scalars, where they are part of the value | trailing-spaces |
truthy | warning | Booleans are true or false. yes, no, on, off in any case are flagged because YAML 1.1 reads them as booleans, and True, FALSE and other casings because they are not portable. Keys are checked too, so GitHub Actions’ on: is reported. Quoted or !!str-tagged values are fine. | no | truthy |
byte-order-mark | warning | No U+FEFF at the start. | yes | none |
Formatting cannot fix the no rules without changing what the file means, or what a YAML 1.1 reader sees. For example, quoting yes keeps the YAML 1.2 meaning, but tools that read YAML 1.1 lose the boolean they expected.
Formatting
The formatter uses the yaml library’s document model, which keeps comments, anchors, aliases, tags, key order, directives and document markers.
- Layout. The chosen indentation, the Sequences option, one space after
:and-, no padding inside{}and[],,between flow items, at most one blank line in a row, no blank lines at the start or end, LF line breaks, no byte-order mark, and a final newline. Inline comments get two spaces before the#. Lines are never wrapped. - Scalars. Numbers keep their spelling (
0x1F,1e3,1.50,+12and big integers stay as written), and so do~,Trueand other null and boolean forms. Plain multi-line scalars and folded (>) scalars are joined onto one line, which leaves their value unchanged. Literal (|) scalars keep their lines, chomping and indentation indicators. - Quotes. With quote style Any, quotes are removed only from strings that are plainly words: they start with a letter,
_or/, contain only letters, digits,_ . / @ + -, parentheses and single spaces, and mean the same string in YAML 1.2 and 1.1. So"yes","on","0755","1.0","null","true","~","2024-01-01","1:20","<<"and""stay quoted. With Single or Double, quoted values switch to that quote character when the content allows (a value containing'or a backslash escape stays double-quoted). - Comments. Every comment is kept, next to the node it describes, and own-line comments are re-indented with their content. A few move to the library’s canonical place. A comment after
key:whose value is on the next line moves above the value. A comment on the line after a short value can become that value’s inline comment. A comment at the end of the file gets a blank line before it. A comment between documents goes just before the next---. - Safety check. The formatted text is parsed again and compared with the original, node by node: values, tags, anchors and alias names. If anything differs, the original text is returned unchanged. One case where this happens is a root block scalar with an indentation indicator, which the library would re-indent incorrectly.
- Only comments. A file with comments but no documents is tidied line by line.
Value
The Tree and JSON tabs (and value in the API) show the data of the first document. When there are several documents, they show an array with one element per document. Merge keys are applied, aliases are expanded, integers beyond 2^53 − 1 lose precision, and .inf and .nan become null. If the aliases would expand past 1,000 copies (a “billion laughs” document), or refer to a collection that contains them, the value is not shown and an anchors warning says why; the YAML is still valid and is still formatted.
YAML → JSON
Warnings (at most 100, then a count) cover plain scalars that YAML 1.1 parsers read differently: the 1.1 booleans (y, n, yes, no, on, off in lower, title and upper case), integers with a leading zero (with the octal value 1.1 would give), base-60 numbers, timestamps, and binary or _-separated numbers. Also: non-string keys converted to strings, two keys that become the same string, extra documents, and integers beyond 2^53 − 1.
Errors stop the conversion and give the line, column, an excerpt, and a code. Parse errors use the library’s codes, for example BAD_INDENT, TAB_AS_INDENT, MISSING_CHAR, DUPLICATE_KEY, UNEXPECTED_TOKEN, BLOCK_AS_IMPLICIT_KEY. Conversion errors:
| Code | Cause |
|---|---|
DUPLICATE_KEY | The same key twice in one mapping (YAML requires unique keys; JSON’s “last one wins” is not applied). |
NON_FINITE_NUMBER | .inf, -.inf or .nan: JSON numbers must be finite. |
COMPLEX_KEY | A mapping or sequence used as a key (? [a, b]). |
CUSTOM_TAG | A tag outside the core schema, with custom tags set to error. |
RECURSIVE_ALIAS | An alias inside the collection it refers to (&a [*a]). |
BAD_ALIAS | An alias with no matching anchor. |
BAD_MERGE | A << value that is not a mapping or a list of mappings. |
RESOURCE_EXHAUSTION | Over 1,000 alias expansions, or over 200,000 values in the output. |
Anchors and aliases. Every alias is expanded into a copy, because JSON has no references. To stop “billion laughs” documents (a few lines of nested aliases that expand to gigabytes), conversion stops after 1,000 alias expansions or 200,000 output values, whichever comes first.
Merge keys. A plain (unquoted) << key whose value is an alias or mapping, or a sequence of them, merges those mappings into the current one. Keys written explicitly in the mapping win, wherever they appear; among several merged mappings, earlier ones win. Merged keys are inserted where the << appears. A quoted "<<" is always an ordinary key.
Tags. The core tags !!str, !!int, !!float, !!bool, !!null, !!map, !!seq and the non-specific ! are applied (!!str 123 is the string "123"). Every other tag, including the YAML 1.1 types !!binary, !!timestamp, !!set, !!omap and !!pairs, follows the custom-tags option. With wrap, the key is the tag as written in short form (!!binary, !Ref).
Keys. JSON keys are strings. A null, boolean or number key becomes its text (1 → "1", true → "true", ~ → "null"), with a warning; if two keys end up equal, the later one wins, with a warning.
Numbers and order. Integers are converted exactly, however many digits they have. Floats are written in the shortest form that round-trips (1.5e3 → 1500). Key order is preserved as written. Comments are discarded (JSON has none).
JSON → YAML
- The input is parsed with the same strict JSON parser as the JSON tool, so errors give line, column and offset, and duplicate keys keep the last value with a warning.
- Output is block style, indented 2 to 8 spaces per level (2 by default), with sequences indented under their key, no
---marker, no line folding, and a final newline. Empty objects and arrays are written{}and[]. - Key order is kept unless Sort keys is on (UTF-16 code unit order, as in the JSON tool).
- Strings are plain when that is unambiguous under both YAML 1.1 and 1.2, double-quoted otherwise. Multi-line strings use literal block scalars (
|, or|-when there is no final newline). - Integers keep every digit. A number with a fraction or exponent stays a float:
1.0→1.0,1e5→100000.0,2.50→2.5,1e-7→1e-7.
API
POST /api/yaml/formatlints and formats in one call. It takesinput(at most 15,000 characters; linting and formatting parse the YAML twice, so use the page for larger files),indent(2or4),indent_sequences(consistent,indentedorflush),max_line_length(0turns the rule off; default 120),document_start(ignore,requireorforbid) andquote_style(any,singleordouble). The response hasvalid,summary(counts by severity),diagnostics,documents,formattedandvalue. Invalid YAML is a 200 response withvalid: falseandformattedandvalueset to null, not an HTTP error.POST /api/convert/yaml-to-jsontakesinput(at most 30,000 characters),documents(firstorall),indent,sort_keys,merge_keysandcustom_tags. The response hasjson(exact text) andvalue(the same data as a JSON value; integers beyond 2^53 − 1 lose precision there, as in any JSON parser).POST /api/convert/json-to-yamltakesinput(at most 100,000 characters),indent(2–8) andsort_keys.
Lint rules
| Rule | Severity | What it checks | Fixed by Format |
|---|---|---|---|
syntax | error | The text is well-formed YAML (errors come from the parser, with their exact position). Wrongly typed core tags such as !!int abc are warnings. | no |
key-duplicates | error | No key appears twice in the same mapping. << merge keys may repeat. | no |
anchors | error | Every alias (*name) refers to an anchor (&name) declared before it in the same document (error). An anchor declared twice is a warning; an anchor no alias uses is info. | no |
braces | warning | No spaces just inside flow mappings: {a: 1}, not { a: 1 }; empty is {}. | yes |
brackets | warning | No spaces just inside flow sequences: [1, 2], not [ 1, 2 ]; empty is []. | yes |
colons | warning | No space before a colon and one space after it (key: value). A space before the colon after an alias (*a : b) is allowed, because it is required there. | yes |
commas | warning | No space before a comma and exactly one space after it ([1, 2]). | yes |
comments | warning | A comment starts with # (a space after the #; #! shebangs on the first line are allowed), and an inline comment is at least 2 spaces after the content. Format fixes the spacing before comments, not the missing space inside them. | no |
comments-indentation | warning | A comment on its own line is indented like the content next to it. Format fixes it, except for a comment just before the closing bracket of a multi-line flow collection. | yes |
document-start | warning | With Document start set to require, every document starts with ---; with forbid, the first document has no --- (later ones need it as a separator). Off by default. | yes |
empty-lines | warning | At most 2 blank lines in a row, and none at the start or end of the file. Blank lines inside block scalars are content and never counted. | yes |
empty-values | info | A mapping key has a value: key: with nothing after it is null, which is often a mistake. Write null or ~ to make it explicit. | no |
hyphens | warning | Exactly one space after the - of a sequence item. | yes |
indentation | warning | Nested content is indented by the configured width (2 or 4 spaces), the root starts at column 1, and sequences under a key are indented (indented), flush with the key (flush), or the same way throughout the file (consistent). | yes |
line-length | warning | Lines are at most the configured length (default 120). A line whose content is a single unbreakable word, such as a long URL, is allowed. | no |
new-line-at-end-of-file | warning | The text ends with a line break. | yes |
new-lines | warning | Line breaks are LF (\n), not CRLF or CR. | yes |
octal-values | warning | No plain integers that read as octal in one YAML version and not the other: 0755 (decimal 755 in YAML 1.2, octal 493 in 1.1) and 0o755 (octal in 1.2, a string in 1.1). | no |
quoted-strings | warning | With Quote style set to single or double, quoted values use that quote character (unless the content needs the other). Off by default. | yes |
trailing-spaces | warning | No spaces or tabs at the end of a line. Format cannot remove the ones that are part of a block scalar value. | yes |
truthy | warning | Booleans are written true or false. yes, no, on, off (any case) are strings in YAML 1.2 but booleans in YAML 1.1; True, FALSE and other casings are booleans, but not portable. | no |
byte-order-mark | warning | No byte-order mark (U+FEFF) at the start. | yes |
Errors make the document invalid. Warnings and information are style findings; the document still parses.
API & MCP
The same logic is available over HTTP and as MCP tools. Unlike this page, these run on the server: see where your data goes.
/api/convert/json-to-yaml Convert JSON to YAML 1.2, quoting strings that YAML 1.1 parsers would misread. GET POST /api/convert/yaml-to-json Convert YAML to JSON under pinned YAML 1.2 core-schema rules, with line/column errors and YAML 1.1 pitfall warnings. GET POST /api/yaml/format Check YAML against yamllint’s rules (same rule IDs) and return the findings with positions, plus a comment-preserving formatted copy.