Working with JSON in JavaScript: Parse, Stringify, and Common Pitfalls
The two functions you need
JavaScript's entire JSON API is two methods on the global JSON object:
JSON.parse(text)— turns a JSON string into a JS valueJSON.stringify(value)— turns a JS value into a JSON string
Everything else is a variation on these.
Pretty-printing with stringify
The third argument controls indentation:
JSON.stringify(obj, null, 2) // two-space indent
JSON.stringify(obj, null, '\t') // tab indent
The second argument is a replacer that lets you filter or transform values on the way out:
// Drop the password before logging
JSON.stringify(user, (key, value) => key === 'password' ? undefined : value)
Transforming values on parse with a reviver
Want to turn ISO date strings back into Date objects?
JSON.parse(text, (key, value) => {
if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
return new Date(value)
}
return value
})
Things that don't survive a JSON round-trip
JSON only knows about strings, numbers, booleans, null, arrays and plain objects. These all get mangled or dropped:
undefined→ omitted from objects, becomesnullin arraysDate→ ISO string (one-way;parsewon't restore it)Map,Set→{}- Functions → omitted
BigInt→ throws a TypeError- Circular references → throws a TypeError
Handling BigInt
JSON.stringify({ id: 9007199254740993n })
// TypeError: Do not know how to serialize a BigInt
Workaround:
JSON.stringify(obj, (k, v) => typeof v === 'bigint' ? v.toString() : v)
Detecting circular references
function safeStringify(obj) {
const seen = new WeakSet()
return JSON.stringify(obj, (k, v) => {
if (typeof v === 'object' && v !== null) {
if (seen.has(v)) return '[Circular]'
seen.add(v)
}
return v
})
}
The number precision trap
JSON has one number type — IEEE-754 doubles. Integers larger than Number.MAX_SAFE_INTEGER (2^53 - 1) lose precision:
JSON.parse('{"id": 9007199254740993}').id // 9007199254740992 — wrong!
Fix: serialize big integers as strings on the server, parse them as BigInt on the client.
Common error: "Unexpected token"
This means JSON.parse was given something that isn't valid JSON. Most often:
- The server returned HTML instead of JSON (check the response status)
- The JSON has a trailing comma or unquoted key
- There's a BOM at the start of the file
Validate your JSON here — it'll point to the exact line and column.
Performance tips
- For large payloads, prefer
fetch'sresponse.json()overJSON.parse(await response.text())— engines can stream-parse. - Don't
JSON.parse(JSON.stringify(obj))to deep clone. UsestructuredClone(obj)instead — it's faster and handles more types. - Profile before optimizing.
JSON.parseis highly tuned and rarely the bottleneck.
Try the tools: JSON Formatter · Validator · Minifier