In short
- Use JSON for data that programs exchange (APIs, stored documents), YAML for config files people edit by hand, and CSV for flat tables headed to a spreadsheet.
- YAML allows comments and is easier to read, but unquoted values can change type: in YAML 1.1 parsers such as PyYAML, the country code NO becomes false.
- YAML 1.2 (2009) cut booleans down to true and false, but many tools still parse YAML 1.1, so quote any string that could look like a number, date or boolean.
- CSV can't nest data or store types; everything is text, and the quoting rules in RFC 4180 are often ignored by the tools that write it.
JSON vs YAML vs CSV: the short answer
Pick by who reads the file. If a program writes it and another program reads it, use JSON: it's strict, small and every language parses it the same way. If people edit it by hand, such as a Kubernetes manifest, a GitHub Actions workflow or a Docker Compose file, use YAML, because it allows comments and has less punctuation. If the data is a table that will end up in Excel or Google Sheets, use CSV.
The formats overlap less than they seem. JSON and YAML describe the same kind of data (nested objects, lists, strings, numbers, booleans, null). CSV describes a single table of rows and columns, with no nesting and no types.
The same data in all three formats
Here's a small product list with a nested object, a list of tags, a boolean and a country code. First as JSON:
[
{
"id": 1,
"name": "Desk lamp",
"price": 24.5,
"in_stock": true,
"origin": "NO",
"tags": ["office", "lighting"],
"size": {"w": 15, "h": 45}
},
{
"id": 2,
"name": "Mug \"Monday\", 350 ml",
"price": 8,
"in_stock": false,
"origin": "SE",
"tags": [],
"size": {"w": 9, "h": 10}
}
]As YAML, exactly as our JSON to YAML converter (which uses the js-yaml 4.1.0 library) writes it. Notice the quotes around 'NO': the library adds them so older YAML parsers don't read the country code as false.
- id: 1
name: Desk lamp
price: 24.5
in_stock: true
origin: 'NO'
tags:
- office
- lighting
size:
w: 15
h: 45
- id: 2
name: Mug "Monday", 350 ml
price: 8
in_stock: false
origin: SE
tags: []
size:
w: 9
h: 10As CSV, the nested size object has to be flattened into columns and the tag list squeezed into one cell. The second name contains a comma and double quotes, so the whole field is wrapped in quotes and each inner quote is doubled:
id,name,price,in_stock,origin,tags,size.w,size.h
1,Desk lamp,24.5,true,NO,office;lighting,15,45
2,"Mug ""Monday"", 350 ml",8,false,SE,,9,10Sizes: 238 bytes as minified JSON, 253 as YAML, 140 as CSV. CSV is smallest because column names appear once, in the header, instead of on every record. That advantage grows with row count, which is why large exports are usually CSV.
JSON vs YAML: syntax and features
| Feature | JSON | YAML | CSV |
|---|---|---|---|
| Specification | RFC 8259 (2017) | YAML 1.2.2 (2021) | RFC 4180 (2005, informational) |
| Comments | No | Yes, with # | No |
| Nesting | Yes | Yes | No |
| Types | String, number, boolean, null, object, array | Same, plus dates and custom tags | None: every field is text |
| Structure from | Brackets and braces | Indentation (spaces only) | Commas and line breaks |
| Multiple documents per file | No | Yes, separated by --- | No |
| Typical use | APIs, app data, logs | Config files, CI pipelines | Spreadsheets, data exports |
JSON's rules are short. RFC 8259 requires UTF-8 when JSON moves between systems, lowercase true, false and null, double-quoted strings, and no trailing commas. It has no comment syntax at all, which is the main reason people reach for YAML in config files. Duplicate keys are a gray area: the RFC says names SHOULD be unique and warns that parsers handle duplicates unpredictably.
YAML 1.2 was published in 2009 with the stated goal of making YAML a strict superset of JSON, so almost every JSON document is also valid YAML. YAML adds anchors and aliases for reusing blocks, multi-line strings with | and >, and several documents in one file. More features means more ways to be surprised, which is the next section.
YAML gotchas: the Norway problem and friends
YAML guesses the type of unquoted values, and the guesses changed between versions. YAML 1.1 treated yes, no, on, off, y and n (lowercase, capitalized or all caps) as booleans. So a list of country codes containing Norway, NO, comes back with false in it. That's the Norway problem.
YAML 1.2's core schema fixed this: only true and false (also True and TRUE) are booleans. But not every parser moved on. We ran the same lines through PyYAML 6.0.3, which still follows YAML 1.1, and js-yaml 4.1.0, which follows YAML 1.2:
country: NO # PyYAML: False js-yaml 4: "NO"
answer: yes # PyYAML: True js-yaml 4: "yes"
version: 3.10 # both: 3.1 (a float)
mode: 0755 # PyYAML: 493 js-yaml 4: 755
zip: 01234 # PyYAML: 668 js-yaml 4: 1234
time: 1:20 # PyYAML: 80 js-yaml 4: "1:20"
size: 1e3 # PyYAML: "1e3" js-yaml 4: 1000Neither library gets everything right for a ZIP code or a version number. The fix is the same everywhere: quote any string that could pass for a number, boolean, date or time, such as "NO", "3.10" and "01234".
Indentation errors
YAML uses indentation for structure, and the 1.2.2 spec forbids tab characters in indentation. A line that's off by one space is either a parse error or, worse, valid YAML with a different meaning:
server:
port: 8080
host: example.com
timeout: 30 # one space short: a parse error
server:
port: 8080
timeout: 30 # no error, but timeout is no longer inside serverRun config files through a linter or a converter before deploying. Converting YAML to JSON with our converter and reading the result shows exactly what nested under what.
Loading untrusted YAML
Some YAML libraries can build language objects from type tags in the file. In Python, use yaml.safe_load; PyYAML's unsafe loaders can construct arbitrary Python objects, which is a code execution risk with input you didn't write. JSON has no such feature, which is one reason APIs use it.
JSON vs CSV: when a table is enough
CSV is the right choice when every record has the same flat fields and the destination is a spreadsheet, a database import or a data tool. It's compact, streams one line at a time and opens anywhere. It breaks down quickly beyond that:
- No nesting. Objects must be flattened into columns like
size.w, and lists must be joined into one cell with a separator you invent. Our JSON to CSV converter flattens nested objects into dot-notation columns for this reason. - No types.
true,24.5and01234are all just text. Spreadsheets guess, and Excel will drop the leading zero from a ZIP code or product code unless the column is imported as text. - Quoting rules. RFC 4180 says fields containing commas, double quotes or line breaks should be enclosed in double quotes, and a quote inside a field is escaped by doubling it. Hand-built CSV that skips this splits rows in the wrong place.
- No single standard. RFC 4180 is an informational memo, not a strict standard. Delimiters (Excel in many European locales uses semicolons), line endings and text encoding vary between tools, so check the settings when an import looks scrambled.
Use JSON when records have different shapes, contain lists or nested objects, or need real types.
When to use YAML (and when not to)
Use YAML for files people maintain: deployment configs, CI workflows, application settings, static site front matter. Comments let you explain why a value is set, and diffs stay readable in code review.
Avoid YAML for data that programs exchange or for large datasets. Its parsers are slower and less consistent than JSON's, the implicit typing above causes silent bugs, and not every language has a YAML 1.2 parser in its standard library while almost every one ships JSON support. If you're generating a file from code and nobody edits it by hand, write JSON.
Converting between JSON, YAML and CSV
JSON to YAML and back is lossless for data, but YAML comments disappear when you convert to JSON, since JSON can't hold them. JSON to CSV loses structure: nested objects become dotted columns and arrays become joined strings, so a round trip may not give you the original back.
- Check that JSON is valid, and find the line and column of an error, with the JSON formatter and validator.
- Convert either way between JSON and YAML with the JSON to YAML converter.
- Turn an array of objects into a spreadsheet with JSON to CSV, which also converts CSV back to JSON.
- Spot what changed between two versions of a config with JSON compare.
If you're passing binary data inside JSON, our explainer on Base64 encoding covers how and what it costs.
Frequently asked questions
Is YAML better than JSON?
For config files that people edit, usually yes, because YAML allows comments and needs less punctuation. For data exchanged between programs, JSON is safer: its rules are stricter, parsers agree with each other, and values don't change type unexpectedly.
Is JSON valid YAML?
Almost always. YAML 1.2 was designed as a superset of JSON, so a YAML 1.2 parser reads nearly any JSON document. Older YAML 1.1 parsers can differ on a few edge cases.
Can JSON have comments?
No. Standard JSON (RFC 8259) has no comment syntax, and strict parsers reject // or /* */. Some tools accept variants such as JSONC, but a normal JSON parser won't.
Why does YAML turn NO into false?
YAML 1.1 treats yes, no, on and off as booleans, so the Norway country code NO is read as false. YAML 1.2 dropped that rule, but parsers such as PyYAML still follow 1.1. Quote the value as "NO" to keep it a string.
Can CSV store nested data?
Not directly. CSV is one flat table, so nested objects have to be flattened into columns such as address.city and lists joined into a single cell. If the nesting matters, use JSON.
Should I use tabs or spaces in YAML?
Spaces. The YAML spec says tab characters must not be used for indentation. Two spaces per level is the most common style.