JSON — JavaScript Object Notation — is a text format for structured data. Douglas Crockford specified it in the early 2000s by taking a subset of JavaScript object literal syntax and freezing it. The whole grammar fits on a single page, which is the main reason it won: a parser is a weekend project in any language, and there is very little to argue about.
That small surface area is also why people trip over it. JSON looks like JavaScript, so developers assume JavaScript rules apply. They do not.
The six value types
A JSON document is exactly one value. That value is one of six types:
- Object — an unordered set of key/value pairs,
{"name": "John"}. Keys must be strings in double quotes. - Array — an ordered list,
[1, 2, 3]. Items may be any value, including a mix of types. - String — double-quoted text,
"hello". Escapes are\",\\,\/,\b,\f,\n,\r,\tand\uXXXX. - Number —
42,-3.5,6.02e23. No leading zeros, no hexadecimal, noNaNorInfinity. - Boolean —
trueorfalse, lowercase. - Null —
null, lowercase.
There is no date type, no integer type distinct from float, no comment syntax, no undefined, and no way to express a reference or a cycle. Everything else you have seen in a JSON file is a convention layered on top — ISO 8601 strings for dates, for instance.
A worked example
{
"user": {
"id": 1001,
"name": "John Doe",
"email": "john@example.com",
"active": true,
"roles": ["admin", "user"],
"address": {
"city": "Chennai",
"country": "India",
"zip": "600001"
},
"createdAt": "2026-01-15T10:30:00Z"
},
"projects": [
{ "id": 1, "name": "Website Redesign", "status": "active" },
{ "id": 2, "name": "Mobile App", "status": "completed" }
]
}Two things are worth noticing. createdAt is a string — JSON has no date type, so the timestamp is encoded by convention and every consumer has to parse it. And zip is a string too, deliberately: postal codes have leading zeros, and "01234" becomes 1234 the moment you store it as a number.
What JSON does not allow
These are all valid JavaScript and invalid JSON. Between them they account for the overwhelming majority of parse errors:
- Trailing commas —
{"a": 1,}and[1, 2,]are errors. - Single quotes —
{'a': 1}is an error; strings and keys use double quotes. - Unquoted keys —
{a: 1}is an error. - Comments — neither
//nor/* */exist in JSON. - `undefined`, `NaN`, `Infinity` — none are JSON values. Use
null. - Leading zeros —
007is an error; write7. - Multi-line strings — a literal newline inside a string is an error; escape it as
\n.
Duplicate keys
The JSON specification permits duplicate keys but does not define what a parser should do with them. In practice, JSON.parse in JavaScript and json.loads in Python both keep the last occurrence; some parsers keep the first; a few raise an error. Never rely on the behaviour — if you are generating JSON, do not emit duplicates.
Numbers are the sharp edge
JSON numbers have no defined precision limit, but JavaScript stores them as IEEE 754 doubles. Any integer beyond 2^53 − 1 loses precision when parsed in a browser or in Node. This is a real, common bug: a 64-bit database identifier such as 9007199254740993 silently becomes 9007199254740992.
The standard fix is to transmit large identifiers as strings. If you are consuming an API that does not, you need a parser that supports BigInt, and you need it consistently on every hop.
Encoding
JSON text is Unicode; UTF-8 is the default and what you should use. Non-ASCII characters can appear literally or as \uXXXX escapes, and both are valid. Characters outside the Basic Multilingual Plane — most emoji — need a surrogate pair when escaped: 😀 is 😀.
A byte order mark at the start of the file is not part of the JSON grammar. Some parsers tolerate it; many do not. Strip it.
JSON and its relatives
- JSONC — JSON with comments, used by VS Code configuration files. Not JSON; strip comments before feeding it to a standard parser.
- JSON5 — a relaxed superset with trailing commas, unquoted keys and single quotes. Convenient for hand-written config, not interoperable.
- NDJSON / JSON Lines — one JSON value per line, used for streaming and logs. Each line is JSON; the file as a whole is not.
- YAML — a different format that happens to be a superset of JSON. See JSON vs YAML.
Working with JSON in practice
When a document is more than a screenful, stop reading it as text. Open it in the JSON viewer and explore it as a tree: collapse what you do not need, search across keys and values, and copy the path to anything you want to reference in code. When a document will not parse, the validator will tell you the line, the column and the reason.
And when you are about to write code against an unfamiliar response, run it through the analyzer first. It will tell you which fields are optional, which are sometimes null, and which change type between records — the three things that break integrations after they ship.