| JSON (RFC 8259) |
|---|
| Strings | Double-quoted text with backslash escapes and \uXXXX; raw UTF-8 allowed outside ASCII. | Single quotes, unescaped control characters (U+0000–001F), raw newlines. | Every key and string value on the wire. |
| Object keys | Any double-quoted string, including empty "". | Unquoted identifiers and single-quoted names. | API field names — the quotes are not optional. |
| Numbers | Decimal integers and fractions with optional exponent and leading minus: -12, 3.5, 2e10. | Hex (0x1F), leading zeros (01), a leading plus (+5), NaN, Infinity. | Counts and measures; keep 64-bit IDs as strings. |
| Commas | Separators between members and between elements. | A trailing comma after the last item. | Machine-generated payloads and diffs. |
| Comments | Nothing — the grammar defines no comment token. | // line comments and /* block */ comments. | Interchange only; keep notes in a sibling field. |
| Top-level value | Any single JSON value — object, array, string, number, boolean, null. | Two consecutive values or a truncated document. | One document per file or per response body. |
| JSON5 |
|---|
| Unquoted keys | Bare ECMAScript identifier names as object keys. | Keys with spaces, dashes, or a leading digit — those still need quotes. | Hand-edited config that reads like source (package.json5). |
| Single quotes | Single- or double-quoted strings, escaped line breaks, backslash line continuations. | Raw unescaped line terminators inside a string. | Config you type by hand. |
| Comments | // line comments and /* block */ comments. | Nested block comments — the first */ closes the whole comment. | Annotating intent in long config files. |
| Trailing commas | A comma after the final member or element. | Skipping a comma between two values — separators are still required. | Lines you add, reorder, and delete often. |
| Extended numbers | Hex (0xFF), leading zeros, a leading dot (.5), a plus sign (+5), Infinity, NaN. | Round-trips through strict JSON.parse — each of these is a syntax error. | Local config only; convert to JSON before shipping. |
| JSONC |
|---|
| JSONC | Strict JSON plus // and /* */ comments. | The other JSON5 extensions — unquoted keys and single quotes stay errors. | VS Code settings.json, tsconfig.json, and other tool config. |
| tsconfig.json | Comments and trailing commas, accepted by the TypeScript compiler. | Values that are not strict JSON. | Compiler options in every TypeScript project. |
| VS Code settings | Comments; the editor's parser also tolerates trailing commas. | Unquoted keys — flagged as invalid. | Per-user and workspace editor settings. |
| Round-trip | Strip the comments, then reuse the file as data. | Feeding raw JSONC to JSON.parse. | Config that is both human doc and machine input. |
| JSONL / NDJSON |
|---|
| JSON Lines | One complete JSON value per line, newline-separated; readers ignore empty lines. | An enclosing array, or one value pretty-printed across lines. | Streaming logs and event exports. |
| Streaming | Parse each line as it arrives; memory stays flat. | Random access to record N without scanning the file. | Tail-and-follow pipelines and HTTP streaming bodies. |
| jq -c | jq -c emits each value on one line. | Piping default pretty-printed jq output onward — it breaks the framing. | Turning pretty JSON into JSONL. |
| Media type | application/x-ndjson; .jsonl and .ndjson file names. | application/json — it says nothing about line framing. | NDJSON HTTP responses and file exports. |
| Text tools | Line-oriented tools: grep, tail -f, wc -l, awk. | Whole-document tools until you join the lines back. | Shell-first debugging of big exports. |
| Quirks |
|---|
| Big integers | Exact integers up to 2^53 − 1 (9007199254740991) in JavaScript. | Precision beyond that — JSON.parse reads 9007199254740993 as 9007199254740992. | Serialize 64-bit and Snowflake IDs as strings. |
| Duplicate keys | Parsers accept them, and most keep the last value. | Nothing enforces uniqueness — the RFC only says names SHOULD be unique. | Generate strictly; lint with a duplicate-key checker. |
| \u escapes | Surrogate pairs for astral characters — 😀 is \ud83d\ude00; raw UTF-8 elsewhere. | Unescaped control characters; lone surrogates are ill-formed Unicode. | Transports that mangle non-ASCII bytes. |
| NaN / Infinity | null as the sanctioned stand-in. | The literals — JSON.stringify(NaN) emits null and JSON.parse rejects the words. | Numeric APIs that must not emit invalid JSON. |
| undefined | JSON.stringify silently drops undefined object properties. | Round-tripping undefined — array slots become null and object keys vanish. | Expect missing keys, not undefined, after a serialize cycle. |
| Key order | Insertion order in JavaScript, with integer-like keys sorted first. | Relying on order — the spec does not guarantee it and serializers reorder. | Sort keys explicitly when output must be deterministic. |