JSON Explained
JSON — JavaScript Object Notation — is the format almost every modern API, config file and log line speaks. Its whole design fits on a napkin: six value types, a handful of punctuation rules, and no ambiguity. That minimalism is exactly why it won. This guide builds JSON up from first principles: what a document is made of, a worked example you can read top to bottom, the strictness rules that trip people up (double quotes only, no trailing commas, no comments), how JSON differs from the JavaScript object literals it resembles, the difference between pretty-printing and minifying, and what the parser is really telling you when it throws an error.
What JSON is, and why it won
JSON is a text-based, language-independent format for structured data. That is the entire pitch, and each word earns its place. Text-based means a JSON document is just a string of characters — you can read it in any editor, diff it in Git, and send it through anything that carries text. Language-independent means it is not tied to JavaScript despite the name: Python, Go, Rust, Java and every other mainstream language ships a parser that turns the same bytes into that language's own maps and lists. Structured means it can nest — objects inside arrays inside objects — so it represents real-world records, not just flat key/value pairs.
Through the 2000s the default interchange format was XML, which is powerful but heavy: opening and closing tags for every field, namespaces, schemas, attributes versus child elements, and a parser you had to think about. JSON, standardised as ECMA-404 and IETF RFC 8259, threw almost all of that away. It maps directly onto the two data structures every language already has — a dictionary (object) and a list (array) — so parsing JSON usually hands you a native value with no ceremony. Less to type, less to transmit, less to get wrong. For the read/write-an-API job that dominates the web, that trade was decisive, and JSON became the lingua franca.
The six value types
A JSON value is one of exactly six things. Learn these and you know the whole grammar:
| Type | Looks like | Notes |
|---|---|---|
| object | {"key": value, …} | Unordered set of pairs; keys are double-quoted strings and must be unique in practice. |
| array | [value, value, …] | Ordered list; order is meaningful and preserved. Values may mix types. |
| string | "hello é" | Double-quoted Unicode text. Escapes: \" \\ \/ \n \t \uXXXX. |
| number | 42, -3.14, 6.022e23 | Decimal only. No leading zeros, no + sign, no NaN/Infinity, no hex. |
| boolean | true / false | Lowercase, always. True or TRUE is invalid. |
| null | null | The explicit "no value". Distinct from a missing key or an empty string. |
Two of these — object and array — are containers; the other four are scalars. A whole JSON document is a single value, so the top level can be any of the six, but in practice it is nearly always an object or an array because those carry structure. Note what is absent: JSON has no date type, no integer-versus-float distinction (a number is just a number), no binary/bytes type, and no undefined. Dates travel as strings (usually ISO 8601 like "2026-07-10T03:00:00Z") and binary travels as Base64 strings, by convention rather than by the format.
A worked example object
Here is a small but complete document that uses every one of the six types at least once. Read it top to bottom:
Walk the types: id and score are numbers (one integer-looking, one with a fraction — JSON does not care which). name is a string. active is a boolean. nickname is null, which says "we know there is no nickname," different from leaving the key out entirely. tags is an array of strings whose order is preserved. address is a nested object. logins is an array of objects — the pattern behind almost every API list response. Nothing here is special or advanced; this is JSON at full stretch. Everything else is just deeper nesting of the same six pieces.
The strictness rules people actually hit
JSON's grammar is unforgiving on purpose — a strict, tiny grammar is what lets a parser in any language agree on exactly what a document means. These are the rules that cause the great majority of real errors:
- Strings and keys use double quotes only.
'name'and"name"look interchangeable but only the double-quoted form is legal. Single quotes are an instant syntax error. - Keys must be quoted.
{width: 20}is valid JavaScript but invalid JSON; it has to be{"width": 20}. Every key is a string, even when it looks like a bare word. - No trailing commas. A comma goes between two elements, never after the last one.
[1, 2,]and{"a": 1,}are both rejected. This is the number-one JSON error. - No comments. Neither
// like thisnor/* like this */exists in JSON. There is nowhere to put a note except inside a real string value. - Booleans and null are lowercase.
true,false,null— neverTrue,FALSEorNone(those come from Python and are a frequent copy-paste bug). - Numbers are plain decimals. No leading zeros (
007), no leading+, no hex (0xFF), and noNaNorInfinity. Use7, and represent "not a number" asnullor a string.
JSON versus JavaScript object literals
The name causes real confusion, so it is worth stating plainly: JSON is not JavaScript. Douglas Crockford took a subset of JavaScript's object-literal syntax and froze it into a data-only format. The resemblance is close enough that pasting valid JSON into a JS file usually works, but the reverse fails constantly, because JavaScript literals allow things JSON forbids:
Four differences appear in those few lines: JSON quotes its keys, uses double quotes for strings, drops the trailing comma, and has no undefined (the nearest equivalent is null, or simply omitting the key). It also has no comments and no functions. A useful mental model: JSON is what you get if you take a JavaScript object literal, forbid everything that is code rather than data, and require every string — including keys — to be double-quoted.
Pretty-print versus minify
These are two views of the exact same data, and switching between them changes nothing about the parsed value. Pretty-printing (also called beautifying or formatting) adds newlines and indentation — two spaces, four spaces, or a tab per nesting level — so a human can follow the structure and so that version control produces clean, line-by-line diffs. The worked example above is pretty-printed. Minifying strips every optional space and newline to produce the smallest valid JSON, which is what you want on the wire or embedded in source:
Both forms parse to an identical value; the whitespace between tokens is not data. The trade is simply readability versus size: minify for transport and storage, pretty-print the moment a human needs to read or debug it. A good formatter can also sort keys alphabetically — purely cosmetic, since a JSON object is unordered, but invaluable for making two API responses diff cleanly. Array order, by contrast, is never reordered, because an array is ordered and that order is part of the data.
Paste any JSON and see it pretty-printed or minified live, with the exact line of the first error flagged — everything runs in your browser, nothing is uploaded.
Reading common parse errors
When a parser rejects a document it usually names the character it choked on, and once you know the grammar those messages are easy to decode. The wording varies by language, but the causes are the same handful:
| Error you'll see | Usual cause | Fix |
|---|---|---|
Unexpected token ' | Single quotes on a key or string | Use double quotes everywhere |
Unexpected token ] or } | Trailing comma before the bracket | Remove the last comma |
Unexpected token T / N | True/False/None from Python | Use true/false/null |
| Expected property name | Unquoted key, e.g. {name: 1} | Quote it: {"name": 1} |
| Unexpected end of JSON input | A closing } or ] is missing | Balance every opening bracket |
| Bad control character in string | A raw tab or newline inside a string | Escape it as \t or \n |
| Unexpected non-whitespace after JSON | Two top-level values, or a stray comment | Wrap in an array; delete comments |
A parser reports the first place the text stopped matching the grammar, which is not always where the mistake feels like it is: a missing closing brace, for instance, is often only noticed at the very end of the file. When an error's location is puzzling, scan backwards from the reported spot for an unclosed bracket, a stray comma, or a quote that was never closed — the parser kept reading hopefully until it ran out of valid options.
Putting it together
JSON is small on purpose. Six value types — object, array, string, number, boolean, null — a strict punctuation grammar with double quotes and no trailing commas or comments, and two interchangeable renderings for humans and machines. That is the whole thing. Its power is not features but agreement: because the rules are so tight and so few, a parser written in any language reconstructs precisely the same data, which is exactly what a data-interchange format needs to do. Keep the six types and the strictness rules in your head and nearly every JSON document you meet, and nearly every error a parser throws, becomes readable at a glance.
Open the JSON Formatter & Validator → to check, pretty-print or minify any document and see the first error's exact line, or browse all Polyatic tools.