JSON Toolkit

JSON, TOML, YAML, or CSON: Choosing a Configuration Format

Bottom line: Config files need comments, dates and multi-line text, which is where JSON falls short. Compare JSON, TOML, YAML and CSON, and see what conversion always loses.

Beginner~9 min readPublished 2026-10-31Updated 2026-10-31
Cover comparing JSON, TOML, YAML, and CSON configuration formats

Bottom line: use JSON for machine exchange, and choose TOML or YAML for human-maintained configuration according to the ecosystem (YAML for Kubernetes and CI, TOML for flat structures or native dates); fall back to JSONC only when you are unsure whether the reader supports the dialect.

JSON exists for machines exchanging data; a configuration file is written by people for people. Mix the two up and you get a config.json that cannot hold a comment and that nobody dares to trim.

1. Start with two different kinds of files

Data interchange and configuration do not share the same goal, even though the same person often writes both on the same machine.

Dimension Data interchange Configuration
Who writes it A program serialising a value A human, or a human editing generated output
Who reads it Someone else's program Your own program
What matters Zero ambiguity, size, parse speed Readability, comments, reviewable diffs
Change frequency Every request Occasionally, with review
Cost of a mistake A 500 response A service that will not start

JSON scores almost perfectly in the left column: minimal grammar, a parser in every language, and no comments means no "comment drifted away from the value" problem. In the right column, its strictness is pure friction: no comments, no trailing commas, no dates, and multi-line text has to be collapsed into one line with \n.

2. The four contenders and their syntax

  • JSON: defined by RFC 8259 and ECMA-404, with exactly six value types: object, array, string, number, boolean, and null. It is the de facto interchange standard and the only format that needs no selection decision.
  • TOML: created by Tom Preston-Werner, with v1.0.0 published in January 2021. Its stated goal is a minimal configuration format with obvious semantics that maps unambiguously to a hash table. Cargo.toml and pyproject.toml use it by default.
  • YAML: the current specification is 1.2.2. Indentation expresses hierarchy, and it supports comments, anchors, and multiple documents. Kubernetes manifests, GitHub Actions, and Ansible all depend on it, at the cost of a large specification and implementation differences.
  • CSON: CoffeeScript Object Notation, which writes configuration using CoffeeScript object literals. Atom's config.cson used it. It supports comments, unquoted keys, and trailing commas, but its ecosystem never left the JavaScript world.

2.1 Capability comparison

Capability JSON TOML YAML CSON
Comments ✗ ✓ # ✓ # ✓ #
Trailing commas ✗ ✓ (arrays, inline tables) ✓ (flow collections) ✓
Unquoted keys ✗ ✓ ✓ ✓
Native date-time ✗ (string only) ✓ four date-time types ✓ (auto-parsed in 1.1) ✗
Multi-line strings ✗ (\n escapes) ✓ """ and ''' ✓ block and folded scalars ✓ heredoc
Integer range Unbounded in spec, double in practice Signed 64-bit, must be lossless Arbitrary precision plus .inf/.nan Follows JavaScript
Nesting Braces and brackets Tables, arrays of tables, dotted keys Indentation Indentation
Indentation-sensitive ✗ ✗ ✓ ✓
null ✓ ✗ ✓ ✓
Tool coverage Every language Mainstream languages Every language, varying implementations JavaScript only

Two cells deserve a note. TOML has no null, which is the most common failure when converting from JSON. YAML's "native date" behaviour means a 1.1 parser turns 2026-10-31 into a date object automatically, so the type drifts across languages.

3. Comments: the one JSON weakness

The conclusion first: if a human maintains the file and needs to explain why a value is what it is, do not use standard JSON.

There are four practical routes, ordered by how invasive they are:

  1. Switch to JSONC, which is standard JSON plus comments and trailing commas. VS Code's settings.json and tsconfig.json use it. The cost is that the reader must use a comment-aware parser such as jsonc-parser; plain JSON.parse fails. Details are in JSON5 and JSONC: JSON with comments.
  2. Keep a sidecar document. config.json stays machine-readable, while config.md explains what each field means and why it holds that value. Both live in the same directory and change in the same commit.
  3. Put explanations in the schema. JSON Schema's description and $comment keywords can document fields, but schemas rarely ship alongside runtime configuration, so the person reading the config may never see them.
  4. Move to TOML or YAML, letting the format itself provide comments that every parser understands.
{
  // Fixed at 8080: the frontend build script reads this port for its proxy
  "port": 8080,
  // Disable watching to avoid exhausting inodes in CI
  "watch": false
}

JSONC is still a dialect: the extension stays .json, but only some tools understand it. When data leaves the team or crosses a service boundary, the line between JSONC and standard JSON has to be documented.

4. Dates and multi-line strings: TOML's home turf

TOML promotes date-time to a first-class type with four variants: offset date-time, local date-time, local date, and local time. Multi-line strings have dedicated syntax that preserves line breaks:

title = "json-toolkit"
created = 2026-10-31T09:00:00+08:00
description = """
A JSON toolkit for developers.
Every operation runs locally in the browser.
"""

The same information in JSON has to demote the date to a string and escape the line breaks:

{
  "title": "json-toolkit",
  "created": "2026-10-31T09:00:00+08:00",
  "description": "A JSON toolkit for developers.\nEvery operation runs locally in the browser."
}

In JSON, "created" is just a string that happens to look like a date, so the type information has to live in a field contract: both sides must agree that the field is always RFC 3339. TOML gives the parser an actual date object with no verbal agreement required.

YAML can also hold multi-line text, but the two block styles mean different things: | preserves line breaks while > folds them into spaces. Choose the wrong one and an address or a SQL statement collapses into a single line, an error that is very hard to catch in review.

5. Numbers: the most overlooked difference

The JSON specification puts no limit on numeric precision, but RFC 8259 also warns that interoperability is safest when numbers are treated as IEEE 754 doubles. In JavaScript, integers above 2^53 - 1 silently lose precision:

JSON.parse('{"id":9007199254740993}').id
// 9007199254740992: the last digit is gone

TOML requires signed 64-bit integers to be handled losslessly and to raise an error rather than truncate silently; floats follow binary64 and may also be inf or nan. YAML 1.1 carries an older burden: 1:30 is parsed as 90 (sexagesimal), and booleans accept yes, no, on, and off. Hence the classic "Norway problem", where the country code NO becomes false.

For money, never rely on floating point in any of these formats: use integer minor units, strings, or a database decimal type. Formatting and precision are covered in more depth in the boundaries of JSON, YAML, and XML conversion.

6. Tables and nesting: TOML's hard boundaries

TOML expresses nesting with tables and arrays of tables:

[server]
port = 8080

[[routes]]
path = "/parse"
method = "POST"

[[routes]]
path = "/minify"
method = "POST"

It has two hard boundaries you must know before converting:

  • A TOML document's root is a table, so a JSON document whose top level is an array (such as [1, 2, 3]) has no legal TOML representation; it must be wrapped as {"items": [...]};
  • TOML has no null, so a JSON null field must either be dropped or replaced with an empty string or a sentinel value, with the semantics pushed onto the consumer.

YAML is the opposite: nesting depth is unlimited, and anchors plus merge keys can reuse fragments:

defaults: &defaults
  retries: 3
  timeoutMs: 5000

server:
  <<: *defaults
  port: 8080

Anchors are a YAML-only capability and a guaranteed loss during conversion: JSON has no reference syntax, so the expanded file grows and nothing records that the two sections used to be the same configuration.

7. Choosing by scenario

Scenario Recommendation Reason
Public APIs, message queues, caches JSON Maximum universality, zero negotiation cost
Application config, flat and typed TOML Comments, dates, lossless integers, stable parser behaviour
Kubernetes, CI, Ansible YAML The ecosystem is locked in; changing format means changing tools
VS Code, tsconfig.json JSONC Natively supported, no new format to introduce
Reusing configuration fragments YAML Anchors and merge keys are the only ready-made option
Generated and machine-only JSON (minified) No comments needed, best size and parse cost
Legacy Atom or CoffeeScript projects CSON, but plan a migration The ecosystem is marginal and migration costs grow with time

One rule of thumb: let the ecosystem choose the configuration format, not personal preference. Writing Rust means Cargo.toml, deploying to Kubernetes means YAML, and building a VS Code extension means JSONC. Only in a new project with no ecosystem constraints is "which one is nicer to write" a real question.

8. Conversion boundaries

Direction Information that is always lost Advice
JSON → TOML null, top-level arrays, keys that cannot be expressed Normalise the structure and drop empty fields first
TOML → JSON Comments, date types, inf / nan Convert dates to RFC 3339 strings
YAML → JSON Comments, anchors and merge keys, tags, multiple documents Expand anchors first, then convert document by document
JSON → YAML No structural loss, but date strings may be auto-parsed Quote date strings
CSON → JSON Comments, CoffeeScript expressions Migrate once; do not sync in both directions

Conversion tools guarantee the values, never the comments. So do not design a two-way pipeline where "JSON is the source and YAML is a build artifact". Either generate in one direction only, or maintain a single source file.

9. Checklist

  • [ ] Document which file types use which format, and list the dialects that are allowed;
  • [ ] Prefer TOML or YAML for human-maintained configuration, and JSON for machine exchange;
  • [ ] Store dates in JSON as RFC 3339 strings and mark the format in the schema;
  • [ ] Represent money and integers above 2^53 as strings or minor units, never as floats;
  • [ ] Validate each format in CI with its own parser, never with JSON.parse for YAML;
  • [ ] Migrate formats in one direction only, and delete the old file so the two cannot drift.

FAQ

Why does converting JSON to TOML fail on some fields?

TOML has no null, and a TOML document's root is a table, so a JSON null field must be dropped or replaced with an empty string or sentinel, and a top-level array must be wrapped as {"items": [...]}. Comments, date types, and inf/nan are also lost when moving in the opposite direction, which is why conversion should be one-way.

Should I keep two configuration files in different formats?

No. Conversion tools guarantee the values but never the comments, so a pipeline where "JSON is the source and YAML is a build artifact" will drift. Either generate in one direction only, or maintain a single source file and delete the old one after migrating.

How do I add comments to a JSON configuration file?

Standard JSON has no comments. You can switch to JSONC (the VS Code dialect, read with jsonc-parser), keep a sidecar document that explains each field, or move to TOML or YAML. Files sent to other systems should stay standard JSON, with explanations living in documentation or a schema.

Is TOML or YAML better for application configuration?

Choose TOML when the structure is flat, mostly key-value pairs, and native dates matter; its semantics are more predictable and parser differences are smaller. Choose YAML when you need deep nesting, multiple documents, anchor reuse, or when the target ecosystem is YAML-first, such as Kubernetes or CI. Both support comments, so the real differentiator is structural complexity and ecosystem lock-in.

Why does NO turn into false in YAML?

YAML 1.1 treats yes, no, on, off, y, and n as booleans, so Norway's country code NO is parsed as false. This is the "Norway problem". Avoid it by using an implementation that follows YAML 1.2, or by quoting every string that could be misinterpreted.

Is CSON still worth using?

Not for new projects. CSON depends on the CoffeeScript ecosystem, has few maintained tools, and has limited editor and CI support; after Atom stopped being maintained its use cases shrank further. If a project already has CSON configuration, schedule a one-time migration to JSON, TOML, or YAML rather than adding more of it.