CSV, JSON, YAML, XML: choosing a data format

These five formats overlap enough that people treat them as interchangeable and differ enough that converting between them silently destroys information. The differences are not stylistic. They are differences in what each format can express at all, and every conversion is a projection onto a smaller space.

The type system is the real difference

Almost every conversion bug traces back to one question: does the format record what type a value is?

CSV and INI do not. Every value is text, and any typing is inferred by whatever reads the file. This is why ZIP codes lose their leading zeros, why part numbers turn into dates, and why a configuration value of false is frequently truthy in the consuming program.

JSON does, but with a limited vocabulary: string, number, boolean, null, array, object. That covers most needs and leaves real gaps. There is no date type, so dates travel as strings by convention and every system agrees on a different convention. There is no integer type distinct from float, and numbers beyond 2^53 lose precision silently in any JavaScript-based consumer, which is why large database identifiers are routinely transmitted as strings.

YAML has JSON types plus implicit resolution rules that try to guess. This is convenient until it is not, which is the origin of the well-known problem where an unquoted NO becomes the boolean false rather than the country code for Norway.

XML has no types at all without an accompanying schema, and with one it has an extremely elaborate type system that almost nobody uses fully.

Structural capability

The second axis is shape. CSV is strictly two-dimensional: rows and columns, nothing nested. JSON and YAML nest arbitrarily. XML nests and additionally distinguishes attributes from child elements, and preserves the order of mixed text and markup.

This is why converting nested JSON to CSV is the conversion that most often goes wrong. There is no correct answer, only a choice between flattening keys into dotted paths, which produces sparse wide tables, and serialising branches into a single cell as embedded JSON, which produces a table you cannot query. Both are defensible and neither round-trips.

Going the other way is safe: CSV maps cleanly onto an array of flat objects. Conversions that expand capability are safe; conversions that reduce it are where information goes missing.

What each format is genuinely best at

Each of these formats won its niche for a reason.

Conversions that lose information

It is worth having a concrete list, because the losses are predictable.

Going in these directions, expect to lose the item named:

Practical defences

Quote aggressively in YAML. Any scalar whose meaning depends on being a string should be quoted, particularly version numbers, country codes, and anything with leading zeros.

Transmit large integers as strings in JSON. Any identifier that might exceed 2^53 will eventually be corrupted by a JavaScript consumer, and the corruption is silent.

Use ISO 8601 for dates everywhere, written as YYYY-MM-DD or with a full timestamp and explicit offset. It sorts lexicographically, no locale misreads it, and it eliminates the ambiguity between American and European day-month ordering.

Normalise XML-derived arrays in code rather than trusting the shape, because the one-item case will differ from the many-item case and it will do so in production.

Validate at boundaries. A schema, whether JSON Schema, XSD, or a runtime validator, catches these problems where they enter your system rather than three services downstream.

Frequently asked questions

Which format should an API return?

JSON, unless you have a specific reason otherwise. Parser support is universal, it is compact, and its type model matches what most languages expect. XML remains appropriate where formal schema validation is contractually required.

Why do my large ID numbers come back wrong?

JavaScript numbers are IEEE 754 doubles, so integers beyond 2^53 cannot be represented exactly. Any JSON parsed in a browser or Node service will silently round them. Transmit such identifiers as strings.

Is YAML safe to use for configuration?

Yes, with two habits: quote any scalar whose meaning depends on being text, and validate against a schema. Its implicit typing rules are the main hazard and quoting neutralises them.

Tools referenced in this guide