JSON Cheatsheet: Syntax, Data Types, Methods & Common Patterns
Last updated:
JSON (JavaScript Object Notation) has 6 data types (string, number, boolean, null, array, object), 4 syntax rules (double-quoted strings, no trailing commas, no comments, no undefined), and 2 core JavaScript methods (JSON.parse() for string-to-object, JSON.stringify() for object-to-string) — this cheatsheet covers every JSON pattern in one reference.
JSON strings must use double quotes (not single quotes), numbers have no separate integer/float types (both are IEEE 754 double-precision floats), and all JSON keys must be strings — common mistakes that cause parse errors account for 80% of JSON debugging time.
This cheatsheet covers JSON syntax and data types, JSON.parse() and JSON.stringify() option flags, JSONPath query syntax, JSON Schema keywords, common REST API JSON patterns, and quick reference for JSON methods in JavaScript, Python, and Go.
JSON Syntax Rules and Data Types Quick Reference
JSON has 4 syntax rules that differ from JavaScript object literals: all strings (keys and values) must use double quotes, trailing commas are not allowed after the last element in objects or arrays, comments are not supported, and the values undefined, NaN, and Infinity are not valid. Violating any of these rules causes JSON.parse() to throw a SyntaxError.
// ── All 6 JSON value types ────────────────────────────────────
{
"string": "Hello, world", // double quotes required
"number": 42, // integer — also IEEE 754 float
"float": 3.14159, // same type as integer
"exp": 1.5e10, // scientific notation ok
"boolean": true, // true / false — lowercase only
"nothing": null, // null — lowercase only
"array": [1, "two", false, null], // ordered, mixed types ok
"object": { "key": "value" } // nested objects ok
}
// ── Valid vs Invalid JSON ────────────────────────────────────
// VALID
{ "name": "Alice", "age": 30 }
[1, 2, 3]
"just a string"
42
true
null
// INVALID — single-quoted strings
{ 'name': 'Alice' }
// INVALID — unquoted key
{ name: "Alice" }
// INVALID — trailing comma
{ "name": "Alice", "age": 30, }
[1, 2, 3,]
// INVALID — comment
{ "name": "Alice" /* the user */ }
// INVALID — undefined / NaN / Infinity (not JSON values)
{ "a": undefined, "b": NaN, "c": Infinity }
// ── What JSON.stringify does with non-JSON values ─────────────
JSON.stringify({ a: undefined, b: NaN, c: Infinity, d: 1 })
// => '{"b":null,"c":null,"d":1}'
// undefined properties are omitted; NaN and Infinity become null
JSON.stringify([undefined, NaN, Infinity])
// => '[null,null,null]'
// undefined in arrays becomes null
// ── Number precision limit ───────────────────────────────────
// IEEE 754 doubles safely represent integers up to 2^53 - 1
Number.MAX_SAFE_INTEGER // 9007199254740991
// Larger integers lose precision — use BigInt + custom reviver
JSON.parse('{"id": 9007199254740993}').id
// => 9007199254740992 (wrong — precision lost)
The number type has no distinct integer and float subtypes — both 42 and 3.14 are the same JSON number type, stored as IEEE 754 double-precision floats. This means integers larger than 2^53 - 1 (9,007,199,254,740,991) cannot be represented exactly in JSON without a custom reviver. When working with database IDs larger than this limit (common with 64-bit integer IDs), represent them as strings in JSON rather than numbers.
JSON.parse() and JSON.stringify() Options Reference
JSON.parse(text, reviver) and JSON.stringify(value, replacer, space) are the two core JSON methods in JavaScript. Both support a second parameter that transforms values during processing — the reviver in parse() and the replacer in stringify(). Understanding these parameters enables date round-tripping, field filtering, circular reference handling, and custom serialization.
// ── JSON.parse(text, reviver) ─────────────────────────────────
// reviver: called bottom-up on every key-value pair
// return value replaces the parsed value; return undefined to delete
// Example 1: convert ISO date strings to Date objects
const data = JSON.parse('{"createdAt":"2026-05-20T10:00:00.000Z","name":"Alice"}',
(key, value) => {
if (typeof value === 'string' && /^d{4}-d{2}-d{2}T/.test(value)) {
return new Date(value)
}
return value
}
)
data.createdAt instanceof Date // true
// Example 2: coerce number strings to BigInt for large IDs
const safe = JSON.parse('{"id":"9007199254740993","name":"Bob"}',
(key, value) => key === 'id' ? BigInt(value) : value
)
// Example 3: delete sensitive fields during parse
const clean = JSON.parse('{"name":"Alice","password":"secret","age":30}',
(key, value) => key === 'password' ? undefined : value
)
// clean => { name: 'Alice', age: 30 }
// ── JSON.stringify(value, replacer, space) ────────────────────
// replacer as ARRAY — field whitelist (only include listed keys)
JSON.stringify({ name: 'Alice', password: 'secret', age: 30 }, ['name', 'age'])
// => '{"name":"Alice","age":30}'
// replacer as FUNCTION — transform each value
JSON.stringify({ name: 'Alice', dob: new Date('1990-01-01'), score: 95.678 },
(key, value) => {
if (value instanceof Date) return value.toISOString().split('T')[0] // date only
if (typeof value === 'number') return Math.round(value)
return value
}
)
// => '{"name":"Alice","dob":"1990-01-01","score":96}'
// space parameter — indentation
JSON.stringify({ a: 1, b: [2, 3] }, null, 2) // 2-space indent
JSON.stringify({ a: 1, b: [2, 3] }, null, 4) // 4-space indent
JSON.stringify({ a: 1, b: [2, 3] }, null, '\t') // tab indent
// ── toJSON() — custom serialization on objects ─────────────────
class Money {
constructor(public amount: number, public currency: string) {}
toJSON() {
// JSON.stringify calls toJSON() if it exists on the value
return `${this.amount} ${this.currency}`
}
}
JSON.stringify({ price: new Money(9.99, 'USD') })
// => '{"price":"9.99 USD"}'
// ── Circular reference handling ───────────────────────────────
// JSON.stringify throws TypeError on circular references
const obj: Record<string, unknown> = { name: 'Alice' }
obj.self = obj // circular!
// JSON.stringify(obj) // throws: TypeError: Converting circular structure to JSON
// Safe stringify with cycle detection
function safeStringify(value: unknown): string {
const seen = new WeakSet()
return JSON.stringify(value, (_key, val) => {
if (typeof val === 'object' && val !== null) {
if (seen.has(val)) return '[Circular]'
seen.add(val)
}
return val
}, 2)
}
The toJSON() method is called by JSON.stringify() before serializing an object — if the method exists, its return value is used instead. The built-in Date object has a toJSON() method that returns an ISO 8601 string, which is why dates serialize to strings automatically. Custom classes can implement toJSON() to control their JSON representation. Note that JSON.parse() does not reverse this automatically — you need a reviver to reconstruct the original type from the serialized form.
JSONPath Syntax Quick Reference
JSONPath is a query language for extracting values from JSON documents. The root of every JSONPath expression is $ (the root element). Child access uses dot notation ($.user.name) or bracket notation ($['user']['name']). JSONPath's most powerful feature is the filter expression [?(@.field operator value)], which selects array elements matching a condition.
// ── JSONPath operator reference ──────────────────────────────
// $ root element (always starts here)
// . child operator: $.store.name
// .. recursive descent: $..name (all "name" at any depth)
// * wildcard: $.users[*] (all array elements)
// [n] array index: $.items[0] (first element)
// [-1] last element: $.items[-1]
// [start:end] slice: $.items[0:3] (first 3, exclusive end)
// [a,b,c] union: $.items[0,2,4] (elements 0, 2, 4)
// [?(@.expr)] filter: $.books[?(@.price < 10)]
// @ current element (used inside filter expressions)
// @.length array length in filter: $.arr[?(@.length > 2)]
// ── 8 example queries ─────────────────────────────────────────
const store = {
"store": {
"name": "My Store",
"books": [
{ "title": "JSON Spec", "price": 4.99, "tags": ["reference"] },
{ "title": "API Design", "price": 14.99, "tags": ["rest", "design"] },
{ "title": "Data Formats", "price": 9.99, "tags": ["reference", "data"] }
],
"owner": { "name": "Alice", "since": 2020 }
}
}
// 1. Simple child access
$.store.name // "My Store"
// 2. Array index
$.store.books[0].title // "JSON Spec"
// 3. Last element
$.store.books[-1].title // "Data Formats"
// 4. All titles (wildcard)
$.store.books[*].title // ["JSON Spec", "API Design", "Data Formats"]
// 5. Recursive descent — all "name" fields at any depth
$..name // ["My Store", "Alice"]
// 6. Filter by price less than 10
$.store.books[?(@.price < 10)] // books with price < 10
// 7. Filter by tag (contains check)
$.store.books[?('reference' in @.tags)] // books with "reference" tag
// 8. Slice — first two books
$.store.books[0:2] // first 2 books (index 0 and 1)
// ── JavaScript implementation ─────────────────────────────────
// npm install jsonpath-plus
import { JSONPath } from 'jsonpath-plus'
const titles = JSONPath({ path: '$.store.books[*].title', json: store })
// => ["JSON Spec", "API Design", "Data Formats"]
const cheap = JSONPath({ path: '$.store.books[?(@.price < 10)]', json: store })
// => [{ title: "JSON Spec", price: 4.99, tags: ["reference"] }]
// ── Python implementation ─────────────────────────────────────
// pip install jsonpath-ng
// from jsonpath_ng import parse
// expr = parse('$.store.books[*].title')
// matches = [m.value for m in expr.find(store)]
// ── jq (command line) — similar but different syntax ─────────
// jq '.store.books[] | select(.price < 10)' store.json
// jq '.store.books[0].title' store.json
// jq '[.store.books[].title]' store.json
JSONPath filter expressions use @ to refer to the current element being tested. Comparison operators ==, !=, <, <=, >, >= work on scalar values; some implementations also support in for array membership and =~ for regex matching. Note that jq uses a different syntax than JSONPath — jq is a full transformation language, not just a query language, and its filter syntax (.store.books[] | select(.price < 10)) differs from JSONPath's bracket filter syntax.
JSON Schema Keywords Reference
JSON Schema is a vocabulary for annotating and validating JSON documents. A JSON Schema is itself a JSON object (or boolean) that describes the structure, constraints, and documentation of a JSON value. The most commonly used draft is Draft 7 (2019) and Draft 2020-12. This reference covers the keywords used in over 90% of real-world schemas.
// ── Type keywords ────────────────────────────────────────────
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object", // "string" | "number" | "integer" | "boolean" | "null" | "array" | "object"
// ── Object constraints ──────────────────────────────────────
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" },
"age": { "type": "integer", "minimum": 0, "maximum": 150 }
},
"required": ["name", "email"], // these keys must be present
"additionalProperties": false, // reject keys not in properties
"minProperties": 1, // at least 1 property
"maxProperties": 10, // at most 10 properties
// ── String constraints ──────────────────────────────────────
// "minLength": 1, minimum string length
// "maxLength": 255, maximum string length
// "pattern": "^[a-z]+$", regex the string must match (ECMA 262)
// "format": "email", semantic format (email, uri, date, date-time, uuid, ipv4)
// ── Number constraints ──────────────────────────────────────
// "minimum": 0, value >= minimum
// "maximum": 100, value <= maximum
// "exclusiveMinimum": 0, value > exclusiveMinimum (Draft 7+)
// "exclusiveMaximum": 100,
// "multipleOf": 0.01, value must be a multiple (e.g. for money)
// ── Array constraints ───────────────────────────────────────
// "items": { "type": "string" }, all items must match schema
// "prefixItems": [schema1, schema2], positional item schemas (Draft 2020-12)
// "minItems": 1, at least 1 item
// "maxItems": 100, at most 100 items
// "uniqueItems": true, no duplicates allowed
// "contains": { "type": "number" }, at least one item matches
// "minContains": 2, at least N items match contains
}
// ── Composition keywords ──────────────────────────────────────
{
// allOf: value must satisfy ALL schemas (intersection)
"allOf": [
{ "type": "object" },
{ "required": ["id"] }
],
// anyOf: value must satisfy AT LEAST ONE schema (union)
"anyOf": [
{ "type": "string" },
{ "type": "number" }
],
// oneOf: value must satisfy EXACTLY ONE schema (exclusive)
"oneOf": [
{ "properties": { "type": { "const": "cat" } }, "required": ["type"] },
{ "properties": { "type": { "const": "dog" } }, "required": ["type"] }
],
// not: value must NOT match schema
"not": { "type": "null" },
// if / then / else — conditional validation
"if": { "properties": { "country": { "const": "US" } }, "required": ["country"] },
"then": { "required": ["state"] },
"else": { "required": ["postalCode"] }
}
// ── $ref — reuse schemas by reference ────────────────────────
{
"$defs": {
"Address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
},
"required": ["street", "city"]
}
},
"type": "object",
"properties": {
"billingAddress": { "$ref": "#/$defs/Address" },
"shippingAddress": { "$ref": "#/$defs/Address" }
}
}
// ── Validation with Ajv (JavaScript) ─────────────────────────
import Ajv from 'ajv'
import addFormats from 'ajv-formats'
const ajv = new Ajv()
addFormats(ajv)
const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) console.log(validate.errors)
The format keyword is advisory by default in most validators — it does not cause validation failure unless the validator is configured with { strict: true } or format validation enabled. Common formats include email, uri, date (YYYY-MM-DD), date-time (ISO 8601), uuid, ipv4, and ipv6. For strict format validation in Ajv, install and enable ajv-formats. See the JSON data validation guide for complete Ajv configuration patterns.
Common REST API JSON Patterns
REST APIs have converged on a small set of JSON response envelope patterns for success, errors, and pagination. Using consistent envelopes makes APIs predictable for clients and enables generic error handling, logging, and pagination UI components. The patterns below cover the most widely adopted conventions, including RFC 7807 for error responses.
// ── Success response envelope ─────────────────────────────────
// GET /api/users/123 → 200 OK
{
"data": {
"id": "123",
"name": "Alice",
"email": "alice@example.com",
"createdAt": "2026-01-15T10:00:00.000Z"
},
"meta": {
"requestId": "req_abc123",
"version": "1"
}
}
// ── Created resource (201) ────────────────────────────────────
// POST /api/users → 201 Created
// Location: /api/users/124
{
"data": {
"id": "124",
"name": "Bob",
"email": "bob@example.com",
"createdAt": "2026-05-20T08:00:00.000Z"
}
}
// ── List response with pagination (page-based) ─────────────────
// GET /api/users?page=2&per_page=20 → 200 OK
{
"data": [
{ "id": "101", "name": "Alice" },
{ "id": "102", "name": "Bob" }
],
"meta": {
"page": 2,
"per_page": 20,
"total": 248,
"total_pages": 13
},
"links": {
"self": "/api/users?page=2&per_page=20",
"first": "/api/users?page=1&per_page=20",
"prev": "/api/users?page=1&per_page=20",
"next": "/api/users?page=3&per_page=20",
"last": "/api/users?page=13&per_page=20"
}
}
// ── Cursor-based pagination (for large/realtime datasets) ──────
// GET /api/feed?cursor=eyJpZCI6MTAwfQ&limit=20 → 200 OK
{
"data": [ /* items */ ],
"pagination": {
"cursor": "eyJpZCI6MTIwfQ", // opaque cursor (base64 encoded)
"has_next": true,
"has_prev": false,
"limit": 20
}
}
// ── Error response — RFC 7807 Problem Details ─────────────────
// Content-Type: application/problem+json
// 422 Unprocessable Entity
{
"type": "https://jsonic.io/errors/validation-error",
"title": "Validation Failed",
"status": 422,
"detail": "The request body contains invalid fields.",
"instance": "/api/users",
"errors": [
{ "field": "email", "code": "INVALID_FORMAT", "message": "Must be a valid email address" },
{ "field": "age", "code": "OUT_OF_RANGE", "message": "Must be between 0 and 150" }
]
}
// ── 401 Unauthorized ──────────────────────────────────────────
{
"type": "https://jsonic.io/errors/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "A valid Bearer token is required."
}
// ── 404 Not Found ─────────────────────────────────────────────
{
"type": "https://jsonic.io/errors/not-found",
"title": "Resource Not Found",
"status": 404,
"detail": "User with id '999' does not exist.",
"instance": "/api/users/999"
}
RFC 7807 (Problem Details for HTTP APIs) defines a standard JSON format for error responses with the Content-Type: application/problem+json header. The five standard fields are type (a URI identifying the problem type), title (human-readable summary), status (HTTP status code), detail (human-readable explanation), and instance (a URI identifying the specific occurrence). Custom fields (like errors for field-level validation errors) are allowed. Using RFC 7807 enables clients to handle errors generically by checking type and status rather than parsing error message strings.
JSON Methods by Language Quick Reference
Every major programming language has built-in or standard library support for JSON serialization and deserialization. The table below covers the primary encode/decode functions across 7 languages, with notes on common options and error handling patterns.
| Language | Parse (string → object) | Serialize (object → string) |
|---|---|---|
| JavaScript / Node.js | JSON.parse(str, reviver?) | JSON.stringify(val, replacer?, space?) |
| Python | json.loads(s, object_hook?) | json.dumps(obj, indent?, default?) |
| Go | json.Unmarshal(data, &v) | json.Marshal(v) |
| C# (.NET) | JsonSerializer.Deserialize<T>(json) | JsonSerializer.Serialize(obj, options?) |
| Java | mapper.readValue(json, Type.class) | mapper.writeValueAsString(obj) |
| PHP | json_decode($json, assoc: true) | json_encode($obj, JSON_PRETTY_PRINT?) |
| Rust | serde_json::from_str<T>(&s) | serde_json::to_string(&v) |
// ── Python ────────────────────────────────────────────────────
import json
from datetime import datetime
# Parse with object_hook to convert dicts to custom objects
data = json.loads('{"name":"Alice","score":95.5}')
pretty = json.dumps(data, indent=2, sort_keys=True)
# Handle non-serializable types with default=
def json_default(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
json.dumps({"created": datetime.now()}, default=json_default)
# ── Go ────────────────────────────────────────────────────────
// json struct tags control field names and omitempty behavior
type User struct {
ID int64 `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"-"` // excluded from JSON output
Nickname string `json:"nickname,omitempty"` // omit if empty string
}
// Unmarshal (parse) — v must be a pointer
var user User
err := json.Unmarshal([]byte(jsonStr), &user)
// Marshal (serialize)
data, err := json.MarshalIndent(user, "", " ") // pretty-print
jsonStr := string(data)
// ── C# (System.Text.Json) ─────────────────────────────────────
using System.Text.Json;
using System.Text.Json.Serialization;
public class User {
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonIgnore]
public string Password { get; set; }
}
var options = new JsonSerializerOptions {
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
string json = JsonSerializer.Serialize(user, options);
User parsed = JsonSerializer.Deserialize<User>(json, options);
// ── Rust (serde_json) ─────────────────────────────────────────
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Serialize, Deserialize)]
struct User {
name: String,
#[serde(skip)]
password: String,
#[serde(rename = "createdAt")]
created_at: String,
}
let json_str = serde_json::to_string(&user).unwrap();
let user: User = serde_json::from_str(&json_str).unwrap();
// Pretty-print in Rust
let pretty = serde_json::to_string_pretty(&user).unwrap();
Error handling patterns differ by language: JavaScript's JSON.parse() throws SyntaxError (wrap in try/catch), Python's json.loads() raises json.JSONDecodeError, Go's json.Unmarshal returns an error value (check with if err != nil), and Rust's serde_json::from_str returns a Result (use .unwrap() in examples, proper error handling in production). For safe JSON parsing in TypeScript with runtime type validation, see the JSON parsing in JavaScript guide.
JSON Tools and Validators Quick Reference
The JSON tooling ecosystem covers online validators, command-line processors, schema validators, IDE extensions, and format converters. Knowing the right tool for each task — validation, querying, transformation, and schema enforcement — avoids writing manual parsing code for common operations.
// ── Online validators & formatters ──────────────────────────
// jsonlint.com — syntax validation with line-level error reporting
// jsonformatter.org — format, validate, minify, compare JSON
// jsonic.io — JSON formatter, validator, JSONPath evaluator, diff
// jsonschema.net — visual JSON Schema editor and validator
// ── Command-line tools ────────────────────────────────────────
// jq — most powerful JSON CLI processor
$ echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' | jq .
$ jq '.users[] | select(.age > 28)' data.json # filter
$ jq '[.users[].name]' data.json # extract array of names
$ jq 'del(.password)' data.json # delete field
$ jq '. + {"new_field": "value"}' data.json # add field
$ jq --arg name "Alice" '.users[] | select(.name == $name)' data.json
// fx — interactive JSON viewer (terminal UI)
$ cat data.json | fx
// jless — read-only pager for JSON (vim-like navigation)
$ jless data.json
// python -m json.tool — built-in pretty-printer (no install needed)
$ echo '{"a":1}' | python -m json.tool
// ── Schema validation libraries ───────────────────────────────
// Ajv (JavaScript) — fastest JSON Schema validator
npm install ajv ajv-formats
// Supports Draft-07, Draft 2019-09, Draft 2020-12
// Zod (TypeScript) — runtime type validation with TypeScript inference
npm install zod
import { z } from 'zod'
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().int().min(0).max(150).optional(),
})
type User = z.infer<typeof UserSchema> // TypeScript type from schema
const result = UserSchema.safeParse(data) // { success, data } or { success, error }
// jsonschema (Python)
pip install jsonschema
from jsonschema import validate, ValidationError
validate(instance=data, schema=schema) # raises ValidationError if invalid
// ── IDE extensions ────────────────────────────────────────────
// JSON Schema Store (SchemaStore.org) — VS Code auto-detects schema from $schema
// Prettier — format JSON files on save (works via .prettierrc config)
// Even Better TOML — useful alongside JSON for config file comparison
// REST Client (VS Code) — send HTTP requests, view JSON responses inline
// ── Conversion tools ─────────────────────────────────────────
// csv-to-json: npm install csvtojson / online: csvjson.com
// xml-to-json: npm install xml2js / online: jsonformatter.org/xml-to-json
// yaml-to-json: npm install js-yaml / online: jsonformatter.org/yaml-to-json
// json-to-csv: npm install json-2-csv
// js-yaml (JavaScript)
import yaml from 'js-yaml'
const obj = yaml.load(yamlString) // YAML → object
const jsonStr = JSON.stringify(obj, null, 2) // object → JSON
For JSON querying in production code, prefer purpose-built libraries (jsonpath-plus for JSONPath, jq for command-line) over hand-written recursive functions — they handle edge cases like recursive descent, filter expressions, and array slices correctly. For schema validation in TypeScript projects, Zod is preferred over raw JSON Schema because it generates TypeScript types automatically from the schema definition, eliminating the need to maintain separate type declarations. See the JSONPath cheatsheet for complete JSONPath syntax reference and the JSON security guide for tool-specific security considerations.
Key Terms
- ECMA-404
- The official specification for the JSON data interchange syntax, maintained by Ecma International (the same standards body responsible for ECMAScript/JavaScript). ECMA-404, first published in 2013 and updated in 2017, defines the JSON grammar in 4 pages — making it one of the shortest specification documents for any widely-deployed data format. It is companion-synchronized with RFC 8259 (IETF), which covers the same syntax but adds interoperability guidance and requires UTF-8 encoding for network interchange. ECMA-404 is the definitive normative reference for the JSON data format grammar.
- IEEE 754 double-precision
- The floating-point number format used to represent all JSON numbers in JavaScript and most other language implementations. IEEE 754 double-precision (64-bit) can represent integers exactly up to 2^53 - 1 (9,007,199,254,740,991) and floating-point numbers with approximately 15-17 significant decimal digits. Numbers outside this range lose precision silently — this is why database IDs larger than
Number.MAX_SAFE_INTEGERshould be represented as strings in JSON. The special values NaN and Infinity, which exist in IEEE 754, are not valid JSON values —JSON.stringify()converts them tonull. - reviver function
- An optional second argument to
JSON.parse()that transforms parsed values before they are returned. The reviver is called bottom-up (leaf nodes first, root last) on every key-value pair in the parsed document, receiving the key name (string) and the already-parsed value. Returning a different value from the reviver replaces the parsed value; returningundefinedremoves the key from the parent object. The most common use of revivers is to convert ISO 8601 date strings back intoDateobjects during parsing, since JSON has no native date type and dates serialize to strings withDate.prototype.toJSON(). The reviver is called with an empty string key ('') for the root value as the final call. - JSONPath
- A query language for selecting values from JSON documents, originally proposed by Stefan Goessner in 2007 as a JSON analog to XPath for XML. JSONPath expressions start with
$(root element) and use dot notation or bracket notation to traverse the document tree. Key operators:..for recursive descent (all levels),*for wildcard,[n]for array index,[start:end]for slicing, and[?(@.field operator value)]for filter expressions. JSONPath was standardized as RFC 9535 in 2024, resolving longstanding ambiguities between different implementations. JSONPath is used in JSON Schema$refresolution, AWS Step Functions, Kuberneteskubectlexpressions, and various API gateway routing rules. - JSON Schema
- A vocabulary for annotating and validating JSON documents, defined at json-schema.org. A JSON Schema is itself a valid JSON document (or the boolean values
trueorfalse) that describes the structure, types, and constraints of a JSON value. JSON Schema supports type checking, string pattern matching, numeric range constraints, array length and item validation, object property requirements, and composition operators (allOf,anyOf,oneOf,not,if/then/else). Major drafts include Draft-07 (widely supported), Draft 2019-09, and Draft 2020-12 (latest). JSON Schema is embedded in OpenAPI specifications for request/response validation and is the format used by JSON Schema Store (schemastore.org) for IDE autocompletion in configuration files. - toJSON method
- A method on JavaScript objects that
JSON.stringify()calls automatically before serializing. If an object has atoJSON()method,JSON.stringify()uses the method's return value instead of the object itself. This enables custom JSON serialization for classes: aMoneyclass withtoJSON() { return `${this.amount} ${this.currency}` }will serialize as a string. The built-inDateobject uses this mechanism —Date.prototype.toJSON()returns an ISO 8601 string, which is why dates automatically serialize to strings rather than throwing an error. ThetoJSON()method is called with the current key name as its argument (matching the reviver pattern), though most implementations ignore the argument.
FAQ
What are the JSON data types?
JSON has exactly 6 value types defined in the ECMA-404 specification: string (a sequence of Unicode characters in double quotes, e.g. "hello"), number (IEEE 754 double-precision float — no separate integer/float types, e.g. 42, 3.14, 1e10), boolean (the literals true or false, lowercase only — "true" as a string is not a boolean), null (the literal null, lowercase — represents intentional absence), array (an ordered list of values in square brackets, e.g. [1, "two", null]), and object (an unordered set of double-quoted-string keys mapped to values, e.g. {"name":"Alice"}). Values not in JSON: undefined, NaN, Infinity, functions, and Date objects. JSON.stringify() silently omits undefined properties and converts NaN and Infinity to null.
What is the difference between JSON.parse() and JSON.stringify()?
JSON.parse(text, reviver?) converts a JSON string into a JavaScript value. It accepts an optional reviver function called bottom-up on every key-value pair — commonly used to convert ISO date strings back into Date objects. It throws SyntaxError on invalid input and must be wrapped in try/catch. JSON.stringify(value, replacer?, space?) converts a JavaScript value into a JSON string. The replacer is either a function (transforms each value) or an array (field whitelist — only listed keys are included). The space parameter (number 0–10 or string up to 10 chars) controls indentation. Key differences: JSON.parse() can reconstruct nested objects and arrays; JSON.stringify() silently drops undefined, converts NaN/Infinity to null, and throws TypeError on circular references. Custom classes can implement toJSON() to control how stringify() serializes them.
Does JSON support comments?
No — JSON does not support comments of any kind. Neither // single-line nor /* */ block comments are valid JSON. This is intentional: Douglas Crockford removed comment support from JSON to prevent comments from being used as parsing directives (as IE did with HTML comments). Attempting to parse JSON with comments using JSON.parse() throws SyntaxError. Workarounds: JSONC (JSON with Comments), used by VS Code for its configuration files and parseable with jsonc-parser; JSON5, a superset that also adds trailing commas, unquoted keys, and single-quoted strings; or a dedicated "__comment" key (works but pollutes data). For configuration files requiring comments, YAML and TOML are popular alternatives. The jsonic.io formatter strips JSONC comments before validating.
What is the difference between JSON null and undefined?
JSON has null as a first-class type — it serializes and round-trips perfectly. JavaScript undefined is not a valid JSON value and behaves differently in every JSON.stringify() context: object properties with undefined values are silently omitted ({"a": undefined, "b": 1} becomes {"b":1}); undefined array elements become null ([undefined, 1] becomes [null,1]); and a top-level undefined value returns the string "undefined" (not valid JSON). This asymmetry causes bugs when round-tripping data: a property that was undefined before stringifying is simply absent after parsing. Rule: use null to represent intentional absence in JSON payloads. In TypeScript, the safe JSON value type is string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue } — which excludes undefined.
What is JSONPath and how do I use it?
JSONPath is a query language for selecting values from JSON documents (analogous to XPath for XML). Every expression starts with $ (root). Core syntax: . (child access, e.g. $.user.name), .. (recursive descent — all levels, e.g. $..name), * (wildcard), [n] (array index), [-1] (last element), [0:3] (slice), and [?(@.price < 10)] (filter expression — selects array elements where condition is true, @ refers to current element). In JavaScript, use jsonpath-plus: JSONPath({ path: "$.store.books[?(@.price < 10)]", json: data }. In Python, use jsonpath-ng. On the command line, jq uses related but distinct syntax: jq '.store.books[] | select(.price < 10)'. JSONPath was standardized as RFC 9535 in 2024. Common uses: API response extraction, JSON Schema $ref resolution, AWS Step Functions, and Kubernetes kubectl expressions.
What are the most common JSON syntax errors?
In order of frequency: (1) Trailing commas — JSON forbids a comma after the last element ({"a":1,"b":2,} invalid; JavaScript object literals allow it). (2) Single-quoted strings — JSON requires double quotes for both keys and string values ({"name":'Alice'} invalid). (3) Unquoted keys — keys must be quoted strings ({ name: "Alice" } invalid). (4) Comments — no comment syntax; // and /* */ both cause SyntaxError. (5) undefined, NaN, or Infinity — none are valid JSON values. (6) Unquoted string values — {"role": admin} where admin should be "admin". (7) Invalid escape sequences — valid escapes are \", \\, \/, \b, \f, \n, \r, \t, \uXXXX. Use the jsonic.io validator or jsonlint.com to pinpoint errors with line numbers.
How do I pretty-print JSON?
In JavaScript: JSON.stringify(value, null, 2) — the third argument is the indent width (2 spaces); use 4 for 4-space or '\t' for tabs. In Python: json.dumps(data, indent=2). In the terminal with jq: echo '{"a":1}' | jq . — jq pretty-prints by default. With Python built-in (no install): echo '{"a":1}' | python -m json.tool. In Node.js: console.log(JSON.stringify(data, null, 2)). In VS Code: open a .json file, press Shift+Alt+F (Windows/Linux) or Shift+Option+F (macOS) to format with Prettier. Online: use the jsonic.io formatter or jsonformatter.org. With jq options: jq --indent 4 for 4-space, jq -c for compact (minified). In Go: json.MarshalIndent(v, "", " "). In Rust: serde_json::to_string_pretty(&v).
What is the JSON specification and who maintains it?
JSON is defined by two synchronized specifications: ECMA-404 ("The JSON Data Interchange Syntax"), maintained by Ecma International, and RFC 8259("The JavaScript Object Notation (JSON) Data Interchange Format"), maintained by the IETF (Internet Engineering Task Force). RFC 8259, published December 2017, obsoleted the earlier RFC 7159 and RFC 4627. Both documents define identical grammars; ECMA-404 is the normative format reference, while RFC 8259 adds interoperability guidance (UTF-8 encoding is required for network interchange) and implementation notes. ECMA-404 is 4 pages long — one of the shortest standards for any widely-used format. JSON was originally specified by Douglas Crockford around 2001, built on a subset of JavaScript syntax. It was first formalized as RFC 4627 in 2006. The specification has not changed since 2017 — JSON's simplicity is intentional and considered a feature.
Further reading and primary sources
- ECMA-404: The JSON Data Interchange Syntax — The official 4-page JSON specification from Ecma International
- RFC 8259: The JSON Data Interchange Format — IETF specification covering JSON syntax, encoding requirements, and interoperability guidance
- JSON Schema: Draft 2020-12 — Latest JSON Schema specification with type, validation, and composition keywords
- RFC 9535: JSONPath — Query Expressions for JSON — IETF standardization of JSONPath syntax, published 2024
- RFC 7807: Problem Details for HTTP APIs — Standard JSON error response format with type, title, status, detail, and instance fields