Skip to content

Developers · 8 min read

JSON vs YAML vs CSV: which data format should you use?

The same product list written three ways, the parsing surprises we reproduced in real YAML libraries, and a plain rule for choosing between them.

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: 10

As 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,10

Sizes: 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

FeatureJSONYAMLCSV
SpecificationRFC 8259 (2017)YAML 1.2.2 (2021)RFC 4180 (2005, informational)
CommentsNoYes, with #No
NestingYesYesNo
TypesString, number, boolean, null, object, arraySame, plus dates and custom tagsNone: every field is text
Structure fromBrackets and bracesIndentation (spaces only)Commas and line breaks
Multiple documents per fileNoYes, separated by ---No
Typical useAPIs, app data, logsConfig files, CI pipelinesSpreadsheets, 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: 1000

Neither 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 server

Run 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.5 and 01234 are 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.

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.

Sources

Published 11 October 2026Written and fact-checked by the ToolzyLab teamEditorial policy