JSON Cheat Sheet
JSON is the standard text format for data in APIs and config files (RFC 8259). Syntax rules, common mistakes, JSON in JavaScript and Python, jq on the command line (jq 1.7+) and JSON Schema basics.
On this page
Data Types #
| Example | Type |
|---|---|
{"name": "Ann", "age": 30} | Object: "key": value pairs; keys are always double-quoted strings |
[1, "two", true, null] | Array: ordered list; items can have different types |
"hello" | String (double quotes only) |
42 / -3.5 / 1e6 | Number (no separate integer and float types) |
true / false | Boolean (lowercase) |
null | Empty value (lowercase) |
Objects and arrays nest freely. A document is one value, usually an object or an array:
{
"id": 1024,
"name": "Sourdough",
"price": 4.5,
"tags": ["bread", "vegan"],
"supplier": { "name": "Funk", "country": "BE" },
"discount": null
}
Not Allowed #
| Invalid | Valid JSON |
|---|---|
{name: "Ann"} | {"name": "Ann"}: keys need double quotes |
{'name': 'Ann'} | {"name": "Ann"}: no single quotes |
[1, 2, 3,] | [1, 2, 3]: no trailing commas (also not in objects) |
// comment / /* comment */ | No comments at all; use a "description" key, or JSONC/JSON5 (see below) |
NaN / Infinity | null, or a string like "NaN" |
undefined | null, or leave the key out |
True / None | true / null (JSON is lowercase, not Python) |
012 / +1 / .5 / 5. / 0xFF | 12 / 1 / 0.5 / 5.0 / 255 |
"line 1 + a real line break | "line 1\nline 2": escape newlines and tabs inside strings |
"\'" / "\x41" | "'" / "A": only the escapes listed below exist |
Strings & Escapes #
| Escape | Meaning |
|---|---|
\" | Double quote |
\\ | Backslash (Windows path: "C:\\Users\\ann") |
\n / \r / \t | Newline / carriage return / tab |
\b / \f | Backspace / form feed |
\/ | Slash (optional; a plain / is fine) |
\u00e9 | Unicode character by its 4-digit hex code (here é) |
\ud83d\ude00 | Characters above U+FFFF are written as a surrogate pair (U+1F600, a smiley) |
Characters U+0000 to U+001F must be escaped. Everything else, including é and emoji, may appear as-is: JSON exchanged between systems must be UTF-8.
Numbers #
| Example | Note |
|---|---|
0 / -7 / 42 | Integers: no leading zeros, no + sign |
3.14 / -0.5 | Decimals need a digit before and after the dot |
1e3 / 2.5E-4 / 1e+2 | Exponent notation |
9007199254740993 | Valid, but JavaScript reads it as 9007199254740992: send big IDs as strings |
0.1 | Usually becomes a binary float; send money as cents (450) or a string ("4.50") |
Accessing Nested Values #
| JavaScript | Python | jq |
|---|---|---|
data.supplier.name | data["supplier"]["name"] | .supplier.name |
data.tags[0] | data["tags"][0] | .tags[0] |
data.tags.at(-1) | data["tags"][-1] | .tags[-1] |
data.missing?.name | data.get("missing", {}).get("name") | .missing.name (gives null) |
data.tags.length | len(data["tags"]) | .tags | length |
Object.keys(data) | list(data) | keys_unsorted (keys sorts them) |
JSON in JavaScript #
| Code | What it does |
|---|---|
JSON.parse(text) | String to value (throws a SyntaxError on invalid JSON) |
JSON.stringify(value) | Value to a compact string |
JSON.stringify(value, null, 2) | Pretty print with a 2-space indent ("\t" for tabs) |
JSON.stringify(user, ["id", "name"]) | Replacer array: keep only these keys |
JSON.stringify(user, (k, v) => k === "password" ? undefined : v) | Replacer function: returning undefined drops a key |
JSON.parse(text, (k, v) => k === "date" ? new Date(v) : v) | Reviver: convert values while parsing |
toJSON() { return ... } | Method that controls how your object is stringified (Date has one) |
await res.json() | Parse a fetch response (it is already an object afterwards) |
body: JSON.stringify(data) | Send JSON with fetch, plus headers: { "Content-Type": "application/json" } |
JSON.stringify({ a: undefined, f() {} }) | {}: undefined and functions are skipped |
JSON.stringify([undefined, NaN, Infinity]) | [null,null,null] |
JSON.stringify(new Date(0)) | "1970-01-01T00:00:00.000Z" (an ISO string) |
JSON.stringify(new Map([["a", 1]])) | {}: convert first with Object.fromEntries(map) (same for Set: [...set]) |
JSON.stringify(10n) | TypeError: BigInt cannot be serialized |
JSON in Python #
| Code | What it does |
|---|---|
json.loads(text) | String to Python object (json.JSONDecodeError on invalid input) |
json.dumps(obj) | Python object to a compact string |
json.dumps(obj, indent=2) | Pretty print |
json.dumps(obj, ensure_ascii=False) | Keep é as is instead of \u00e9 |
json.dumps(obj, sort_keys=True) | Sort keys (stable output for diffs and tests) |
json.dumps(obj, separators=(",", ":")) | Smallest output, no spaces |
json.dumps(obj, default=str) | Convert unsupported types (datetime, Decimal, UUID) with str() |
json.dumps(obj, allow_nan=False) | Raise an error for nan/inf instead of writing invalid JSON |
json.load(f) / json.dump(obj, f) | Read from / write to an open file |
python3 -m json.tool data.json | Validate and pretty-print a file from the terminal |
Types map as object = dict, array = list (tuples become arrays), true/false = True/False, null = None. Non-string dict keys become strings: {1: "a"} is written as {"1": "a"}.
import json
with open("data.json", encoding="utf-8") as f:
data = json.load(f)
data["count"] += 1
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
jq: Read & Filter #
| Code | What it does |
|---|---|
jq . data.json | Pretty print with colors (and validate: errors show line and column) |
curl -s URL | jq . | Pretty print an API response |
jq -c . data.json | Compact output on one line |
jq .name data.json | One field (.supplier.name for nested fields) |
jq '.tags[0]' / jq '.tags[-1]' | First / last array item |
jq '.tags[]' | Every item, one per line |
jq -r '.name' | Raw output: strings without quotes (for shell scripts) |
jq '.tags | length' | Length of an array, object or string |
jq 'keys' | Object keys, sorted |
jq '.users[] | select(.age >= 18)' | Only items that match a condition |
jq '.users[] | select(.name | test("^a"; "i"))' | Regex match, case-insensitive |
jq '.discount // 0' | Fallback value when the result is null or false |
jq -e '.ok' > /dev/null | Exit code 1 if the result is null or false (for scripts) |
jq: Transform #
| Code | What it does |
|---|---|
jq '.users | map(.name)' | Array of one field: ["Ann","Bob"] (same as [.users[] | .name]) |
jq '.users[] | {name, email}' | New objects with only some fields |
jq '.price = 5' / jq '.price += 1' | Set / update a value |
jq 'del(.discount)' | Remove a key |
jq '.tags |= map(ascii_upcase)' | Update a value with a filter |
jq '.users | sort_by(.age)' | Sort by a field (reverse for descending) |
jq '.users | group_by(.city)' | Group into arrays by a field |
jq '[.users[].city] | unique' | Unique values, sorted |
jq '.users | map(.age) | add / length' | Average |
jq -r '.users[] | "\(.name): \(.age)"' | String interpolation |
jq -r '.users[] | [.name, .age] | @csv' | CSV output (@tsv for tab-separated) |
jq --arg n "$NAME" '.users[] | select(.name == $n)' | Pass a shell variable as a string (--argjson for numbers/JSON) |
jq -s '.' a.json b.json | Slurp: read all inputs into one array |
jq -n '{a: 1, b: [2, 3]}' | Build JSON without an input file |
jq '...' in.json > tmp.json && mv tmp.json in.json | Edit a file "in place" (jq has no -i option) |
JSON Schema #
A JSON Schema describes what valid data looks like. Editors (VS Code) use it for autocomplete and validation; libraries like ajv (JavaScript) and jsonschema (Python) validate data in code.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 1 },
"price": { "type": "number", "minimum": 0 },
"size": { "enum": ["S", "M", "L"] },
"tags": { "type": "array", "items": { "type": "string" } }
},
"required": ["name", "price"],
"additionalProperties": false
}
| Keyword | Meaning |
|---|---|
"type" | "string", "number", "integer", "boolean", "object", "array", "null" (or a list of them) |
"required" | Keys that must be present (properties are optional by default) |
"additionalProperties": false | Reject keys that are not listed in properties |
"minimum" / "maxLength" / "minItems" | Limits for numbers, strings, arrays |
"pattern": "^[A-Z]{2}$" | Regex that a string must match |
"format": "date-time" | Known format (email, uri, uuid...); many validators only check it when enabled |
"$ref": "#/$defs/address" | Reuse a definition from "$defs" |
"$schema": "./product.schema.json" | In a data file: VS Code picks up the schema for autocomplete |
Related Formats #
| Format | What it is |
|---|---|
.jsonl / .ndjson | JSON Lines: one compact JSON value per line; for logs, streams and big exports (jq -c '.[]' turns an array into lines) |
.jsonc | JSON with comments; VS Code settings.json and tsconfig.json use it (trailing commas are tolerated there too) |
.json5 | JSON5: comments, trailing commas, single quotes, unquoted keys, hex, Infinity; needs a JSON5 parser |
.geojson | GeoJSON: JSON for map shapes and coordinates |
.yaml | YAML 1.2 is a superset of JSON: every JSON file is valid YAML |
JSON.parse(), json.loads() and jq accept strict JSON only: comments or trailing commas from JSONC/JSON5 make them fail.
MIME Type & Files #
| Code | What it does |
|---|---|
application/json | The official MIME type (always UTF-8, no charset needed) |
Content-Type: application/json | Header for a request or response with a JSON body |
Accept: application/json | Ask a server to answer in JSON |
application/problem+json | Standard error responses for HTTP APIs (RFC 9457) |
application/x-ndjson | Common (unregistered) type for JSON Lines |
.json | File extension; save as UTF-8 without a BOM, 2-space indent is the usual style |
Tips #
- Never build JSON by gluing strings together. Use
JSON.stringify()orjson.dumps()so quotes and backslashes are escaped correctly. Unexpected token '<'while parsing means you received HTML (often an error page), not JSON: check the URL and status code.- A string full of
\"(like"{\"a\":1}") means the data was stringified twice. - Store dates as ISO 8601 strings with a time zone (
"2026-10-11T09:30:00Z"); JSON has no date type. - Duplicate keys are not an error in most parsers: JavaScript and Python silently keep the last value.
- In Bash, wrap jq filters in single quotes. In Windows
cmd, use double quotes and escape inner quotes as\".
Nothing on this sheet matches “”.