JSON Syntax Rules

Every JSON syntax rule with examples: strings, numbers, objects, arrays, escaping, and the specific ways JSON is stricter than JavaScript object literals.

8 min read

The whole grammar

JSON's complete grammar fits on a single page, which is unusual for a data format and entirely intentional. There are six types: four primitives and two containers.

TypeExampleRules
string"Ada"Double quotes only; certain characters must be escaped
number42, -1.5e3Decimal only; no leading +, no leading zeros, no hex
booleantrue, falseLowercase only
nullnullLowercase only
object{"a": 1}Unordered pairs; keys must be quoted strings
array[1, 2]Ordered; values may be of mixed type

Under RFC 8259, any of these six may be the top level of a document. 42 and "hello" are each complete, valid JSON. The older RFC 4627 required an object or array at the root; that restriction was removed and the current standard does not have it.

Strings

A JSON string is zero or more Unicode characters wrapped in double quotes. Single quotes are never valid.

Three things must be escaped inside a string:

  • the double quote — \"
  • the backslash — \\
  • any control character below U+0020

Control characters have short escape forms: \n newline, \t tab, \r carriage return, \b backspace, \f form feed. Any character may also be written as a \uXXXX escape. The forward slash may optionally be escaped as \/ — this is permitted but never required, and exists because </script> inside embedded JSON can terminate an HTML script tag early.

{
  "quote": "She said \"hello\"",
  "path": "C:\\Users\\Ada",
  "multiline": "line one\nline two",
  "unicode": "caf\u00e9",
  "emoji": "🎉"
}

A literal newline inside a string is invalid — it must be written as \n. This is what produces the "bad control character" error when text is pasted from a file.

Characters outside the Basic Multilingual Plane, such as emoji, may be written literally in a UTF-8 document or as a surrogate pair of \uXXXX escapes.

Numbers

JSON numbers are decimal, optionally signed, optionally fractional, optionally with an exponent. There is no distinction between integer and float1 and 1.0 are the same number.

Invalid, despite being valid in many languages:

InvalidWhyWrite instead
+5No leading plus5
.5Needs a leading digit0.5
5.Needs a trailing digit5.0
007No leading zeros7
0x1FNo hexadecimal31
NaN, InfinityNot JSON valuesnull or a string
1_000No separators1000

The precision trap. The specification does not mandate a numeric precision, but virtually every parser uses IEEE 754 doubles. Integers above 2^53 (9,007,199,254,740,992) silently lose precision:

JSON.parse('{"id": 9007199254740993}').id
// → 9007199254740992   ← the value changed

This bites 64-bit database IDs and snowflake identifiers. The standard fix is to transport large integers as strings and convert at the boundary.

Objects

An object is an unordered set of key/value pairs inside braces. Every key must be a double-quoted string — not an identifier, not a number, not single-quoted.

{
  "id": 42,
  "name": "Ada",
  "address": { "city": "London" },
  "roles": ["admin"]
}

Two consequences of "unordered" worth internalising:

Key order carries no meaning. Parsers generally preserve insertion order in practice, but the specification does not require it. Never build logic that depends on it.

Duplicate keys are undefined behaviour. {"a": 1, "a": 2} is not forbidden by the grammar, but the spec does not say which value wins. Most parsers take the last. Some security issues have come from two systems in a pipeline resolving duplicates differently — do not produce them.

An empty object, {}, is valid.

Arrays

An ordered list of values in square brackets. Order is significant. Values may be of mixed type, and may nest:

[1, "two", true, null, {"a": 1}, [2, 3]]

Empty arrays are valid. Trailing commas are not.

How JSON is stricter than JavaScript

Nearly every JSON parse error traces to this gap. JSON's syntax was derived from JavaScript object literals, but the two are not the same language, and JavaScript has grown more permissive since JSON was frozen.

// Valid JavaScript — every line is invalid JSON
{
  name: 'Ada',          // unquoted key, single quotes
  age: 36,              // trailing comma below
  tags: ['a', 'b',],    // trailing comma
  // a comment
  big: 1_000_000,       // numeric separator
  nothing: undefined,   // not a JSON type
}
{
  "name": "Ada",
  "age": 36,
  "tags": ["a", "b"],
  "big": 1000000,
  "nothing": null
}

The five rules that cause the overwhelming majority of failures:

  1. Double quotes only — keys and string values alike.
  2. No trailing commas — valid in modern JS, invalid in JSON.
  3. No comments — neither // nor /* */.
  4. Plain decimal numbers — no +, no leading zeros, no hex, no NaN, no Infinity.
  5. Lowercase literals onlytrue, false, null. Not True, not NULL.

Also not JSON types: undefined, Date, RegExp, Map, Set, BigInt, and functions. JSON.stringify drops undefined and functions from objects, and turns them into null inside arrays.

What JSON has no type for

Three things you will need constantly, and the conventions that fill the gap:

Dates. No date type. Use ISO 8601 strings in UTC: "2026-07-29T10:45:00Z". This sorts lexicographically, which is a useful property. Avoid Unix timestamps in public APIs — they are ambiguous about seconds versus milliseconds.

Binary data. No binary type. Base64-encode it into a string, and expect roughly 33% size overhead.

Money. No decimal type, and floats cannot represent 0.1 exactly. Use integer minor units (1099 for £10.99) or a string ("10.99"). Never a float.

JSON Best Practices covers these conventions in more depth.

Checking a document against the rules

The fastest way to test whether something is valid JSON is to format it — a formatter must parse before it can print, so invalid input produces an error rather than output.

Validate your JSON →

For structural validation — required fields, types, permitted values — syntax checking is not enough. See JSON Validation for JSON Schema.

Frequently asked questions

Can JSON keys be unquoted?

No. Every JSON key must be a double-quoted string. {name: "Ada"} is a valid JavaScript object literal but invalid JSON — it must be {"name": "Ada"}. This is the most common source of confusion, because code copied out of a .js file looks correct but will not parse.

Does JSON allow single quotes?

No. JSON permits double quotes only, for both keys and string values. {'a': 1} is invalid. JavaScript accepts single quotes in object literals, which is why this mistake is so frequent when copying between the two.

Can JSON have trailing commas?

No. A comma after the last element of an object or array is invalid JSON, even though modern JavaScript permits it and most linters encourage it. This is the single most common JSON parse error. Some relaxed parsers such as JSON5 and VS Code's JSONC accept trailing commas, but a standards-compliant parser will reject them.

Can JSON contain comments?

Not under the specification. Douglas Crockford removed comments deliberately, to stop implementers using them to carry parsing directives. Some tools accept a relaxed superset — VS Code calls it JSONC and uses it for settings.json and tsconfig.json — but a compliant parser rejects them. If you need a note in the data, use a regular key such as "_comment".

What characters must be escaped in JSON strings?

Inside a string you must escape the double quote (\"), the backslash (\\), and all control characters below U+0020. Common control characters have short forms: \n for newline, \t for tab, \r for carriage return, \b for backspace, and \f for form feed. Any other character can be written literally or as a \uXXXX escape. The forward slash may optionally be escaped as \/, but does not have to be.

More in JSON Guide

← Back to JSON Guide