JSON Syntax Rules: The RFC 8259 Grammar & Escaping Guide
When software developers write configuration files, build RESTful APIs, or serialize database records, they rely on JavaScript Object Notation (JSON) as the default data interchange format. Because JSON syntax looks almost identical to standard JavaScript object literals, developers frequently assume the two formats share the same permissive parsing rules.
This assumption leads to persistent production bugs. JavaScript allows single quotes, unquoted dictionary keys, trailing commas, comments, and values like undefined or NaN. JSON allows none of these.
Governed by the Internet Engineering Task Force (IETF) standard RFC 8259 (and the identical Ecma International standard ECMA-404), JSON is a strict, minimalist grammar designed to be completely language-agnostic. A JSON parser is a zero-tolerance state machine: a single unescaped quote, an extra comma, or a leading zero on a number will cause the parser to reject the entire document. Understanding the formal syntax rules of RFC 8259, how escape sequences operate at the byte level, and what edge cases break parsers is essential for building resilient software systems.
1. The Core Grammar: The Six Legal JSON Data Types
Under RFC 8259, JSON can represent exactly six data types. Any value outside this list cannot be serialized into JSON:
- Strings: Sequences of zero or more Unicode characters enclosed strictly in ASCII double quotation marks (
"). Single quotes (') are illegal. - Numbers: Base-10 decimals, including integers, fractions, and scientific exponents (e.g.,
42,-18.5,2.997e8). Leading zeros (05) and hex values (0xFF) are prohibited. Special constants likeNaNandInfinityare illegal. - Objects: An unordered collection of key-value pairs wrapped in curly braces (
{}). All keys must be double-quoted strings. - Arrays: An ordered sequence of zero or more values wrapped in square brackets (
[]), separated by commas. - Booleans: Represented strictly by lowercase literals:
trueorfalse. - Null: Represented strictly by the lowercase literal:
null.
2. The Universal Root Element Rule
A common misconception is that a valid JSON document must have an object ({}) or an array ([]) as its root container. While early specifications required this, **RFC 8259 allows any valid data type to serve as the top-level root element**.
A file containing simply the string "Hello", the number 42, or the literal true is 100% valid JSON under current web specifications.
3. Character Escaping Sequences (RFC 8259 Section 7)
Because strings are bounded by double quotes and cannot contain raw ASCII control characters (bytes 0–31), RFC 8259 defines **eight two-character escape sequences** using the reverse solidus (\):
| Escape Token | Character Represented | Code Point | Technical Use Case |
|---|---|---|---|
\" | Quotation mark | U+0022 | Escaping inner quotes in strings |
\\ | Reverse solidus (Backslash) | U+005C | Escaping file paths & regexes |
\/ | Solidus (Forward slash) | U+002F | Preventing </script> HTML exploits |
\n | Line feed (Newline) | U+000A | Multi-line text representation |
\r | Carriage return | U+000D | Windows CRLF line endings |
\t | Horizontal tab | U+0009 | Tabular data indentation |
\uXXXX | Unicode code point | Any | Escaping arbitrary Unicode glyphs |
4. The 4 Most Dangerous JSON Syntax Edge Cases
1. The Trailing Comma Hazard
In JavaScript, trailing commas after the final array or object item are recommended. In JSON, trailing commas are strictly illegal:
{"title": "Web Tools", "active": true,}
✔ Valid RFC 8259 JSON:
{"title": "Web Tools", "active": true}
2. The 64-Bit Integer Precision Trap
JSON parsers evaluate numbers using IEEE 754 double-precision floating-point arithmetic. Numbers larger than 253 - 1 (such as database primary keys or Twitter Snowflake IDs) will experience silent mathematical rounding:
The Silent Corruption:
const data = JSON.parse('{"id": 1152921504606846976}');console.log(data.id); // 1152921504606847000 (Corrupted!)
The Fix: Always serialize large integers as strings across API boundaries ({"id": "1152921504606846976"}).
3. Invisible UTF-8 Byte Order Marks (BOM)
Text editors on Windows often prepend the invisible byte sequence 0xEF, 0xBB, 0xBF (\uFEFF) to the beginning of files. While humans see a standard opening brace, strict JSON parsers throw an unexpected token error at position zero. Always export JSON files as UTF-8 without BOM.
4. Binary Payloads
Because JSON is strictly textual, binary streams, images, and raw buffers cannot be embedded directly. They must be encoded to text first using Base64 conversion.
5. Testing and Validation Tools
To validate, format, and inspect complex payloads with standard 2-space indentation, test your data locally using the Urban Mixo JSON Formatter & Validator. Once validated, you can strip whitespace and compress the payload for production using our JSON Minifier.
Frequently Asked Questions
Why does JSON forbid comments?
Douglas Crockford intentionally removed comments from the specification to prevent developers from adding parsing directives or environment-specific instructions. By eliminating comments, JSON guarantees that all parsers interpret the exact same data without implementation divergence.
Can a JSON key be a number or a boolean?
No. In an object key-value pair, the key must always be a string enclosed in double quotes. A key written as {42: "value"} is invalid. It must be written as {"42": "value"}.
How do I represent dates in JSON?
RFC 8259 defines no native date type. The universal industry standard is formatting dates as ISO 8601 strings in UTC time: "2026-09-15T14:30:00Z".
Can a JSON file be completely empty?
No. An empty file containing zero bytes is invalid JSON. A valid JSON document must contain at least one complete value token (such as {} for an empty object, [] for an empty array, or null).
Why does JSON use double quotes instead of single quotes?
The C and Java conventions that inspired JSON distinguish between single characters (single quotes) and multi-character string sequences (double quotes). To maintain universal interoperability across languages, double quotes were chosen as the unambiguous string delimiter.