What JSON Is
JSON (JavaScript Object Notation) is a lightweight text format for representing structured data. It was derived from JavaScript object literal syntax, but it is language-independent — every mainstream programming language has a JSON parser in its standard library or as a first-party package.
JSON is used for API responses, configuration files, data exchange between services, and local storage. Its success comes from being human-readable, minimal, and unambiguous.
The Six Value Types
JSON supports exactly six types — no more, no less:
- String:
"hello world"— always double-quoted, never single quotes - Number:
42,3.14,-7,1.5e10— no special integer vs float distinction - Boolean:
trueorfalse— lowercase, no quotes - Null:
null— represents absence of value - Array:
[1, "two", true, null]— ordered list, heterogeneous types allowed - Object:
{"key": "value"}— unordered map of string keys to any value
Notable omissions: no undefined, no NaN, no Infinity, no Date type, no comments. These are by design — they make parsing deterministic across implementations.
Syntax Rules
JSON is strict. Any deviation produces a parse error.
- Object keys must be strings:
{"name": "Alice"}is valid;{name: "Alice"}is not - Strings must use double quotes:
"hello"is valid;'hello'is not - No trailing commas:
[1, 2, 3,]is invalid;[1, 2, 3]is correct - No comments:
// commentor/* comment */cause parse errors - Numbers have limits: Integers beyond 2^53 − 1 lose precision in JavaScript's
JSON.parse(); use strings for large IDs
Common Parse Errors
// INVALID: single quotes
{ 'name': 'Alice' }
// INVALID: trailing comma
{ "items": [1, 2, 3,] }
// INVALID: comment
{ "version": 1 // app version }
// INVALID: undefined value
{ "result": undefined }
// INVALID: unquoted key
{ name: "Alice" }
// VALID equivalents
{ "name": "Alice" }
{ "items": [1, 2, 3] }
{ "version": 1 }
{ "result": null }
{ "name": "Alice" }
Parsing in Different Languages
// JavaScript
const obj = JSON.parse('{"name":"Alice","age":30}')
const str = JSON.stringify(obj, null, 2) // 2-space indent
// Python
import json
obj = json.loads('{"name":"Alice","age":30}')
str = json.dumps(obj, indent=2)
// Go
import "encoding/json"
type Person struct { Name string `json:"name"`; Age int `json:"age"` }
var p Person
json.Unmarshal([]byte(input), &p)
out, _ := json.MarshalIndent(p, "", " ")
// Java (Jackson)
ObjectMapper mapper = new ObjectMapper()
Person p = mapper.readValue(input, Person.class)
String out = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(p)
JSON vs JSON5
JSON5 is a superset of JSON designed to be more human-friendly. It adds features that JSON deliberately excludes:
- Single-quoted strings:
'hello' - Trailing commas:
[1, 2, 3,] - Comments:
// lineand/* block */ - Unquoted keys:
{name: "Alice"} - Multi-line strings via backslash continuation
- Numeric values like
Infinity,-Infinity,NaN, and hexadecimal literals
JSON5 is great for configuration files where humans edit it directly (e.g., tsconfig.json with comments is technically JSON5-compatible). Never use it for API payloads — most HTTP clients and servers expect strict JSON.
JSON Schema: Validating Structure
JSON Schema is a separate standard for describing what a valid JSON document should look like. A schema is itself a JSON document:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["id", "name"],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string", "minLength": 1 },
"email": { "type": "string", "format": "email" },
"tags": { "type": "array", "items": { "type": "string" } }
},
"additionalProperties": false
}
Validators (Ajv in JavaScript, jsonschema in Python) check a document against a schema at runtime. This is how API libraries like Fastify, tRPC, and OpenAPI validate request bodies without writing manual validation logic.
Working with Large Numbers
JavaScript's JSON.parse() converts all numbers to IEEE 754 doubles. Integers above 2^53 − 1 (9,007,199,254,740,991) lose precision silently. This is a real problem with database IDs from systems like Snowflake (Twitter) or PostgreSQL bigint.
// Problem: precision lost
JSON.parse('{"id": 9999999999999999}')
// → { id: 10000000000000000 } ← wrong!
// Solution: send large integers as strings
JSON.parse('{"id": "9999999999999999"}')
// → { id: "9999999999999999" } ← correct
Performance Tips
- Minimize whitespace in transit: Use
JSON.stringify(data)(no indent) for API responses; only use pretty-print for debugging - Parse once, reference many times: Do not call
JSON.parse()inside a loop if the input does not change - For very large payloads: Use streaming parsers (JSONStream in Node.js, ijson in Python) instead of parsing the entire document into memory
- For repeated serialization: Libraries like fast-json-stringify (Node.js) use a schema to serialize 2-5x faster than
JSON.stringify()