JSON in JavaScript: parse, stringify, and pretty-print
A snip.tools guide · runs alongside the JSON formatter
Prefer to just run it? Use the free JSON formatter — no install, in your browser.
Open the JSON formatter
JSON is the lingua franca of the web — every API response, config file and localStorage value is
a JSON string. JavaScript gives you exactly two functions to move between that text and live objects:
JSON.parse and JSON.stringify. They're simple on the surface but have a handful of
behaviours worth knowing well, because that's where the bugs hide. (When you just want to eyeball or fix a
blob, paste it into our in-browser JSON formatter.)
JSON.parse: text into a value
JSON.parse takes a JSON string and returns the JavaScript value it describes — an
object, array, number, string, boolean or null. The types come back real: a true
in the text becomes a boolean, not the word "true".
const text = '{"name":"Ada","langs":["JS","Rust"],"active":true}';
const obj = JSON.parse(text);
obj.name; // "Ada"
obj.langs[0]; // "JS"
obj.active; // true (a real boolean, not the string "true")
The input must be strict JSON: double-quoted keys and strings, no trailing commas, no
comments, no single quotes. That strictness is the most common source of the
SyntaxError people hit — more on debugging that below.
JSON.stringify: value into text
Going the other way, JSON.stringify serialises a value to a compact JSON string with no
whitespace — ideal for sending over the network or storing:
const user = { name: 'Ada', langs: ['JS', 'Rust'], active: true };
JSON.stringify(user);
// '{"name":"Ada","langs":["JS","Rust"],"active":true}' Pretty-printing with indentation
The third argument controls indentation. Pass a number for that many spaces per level, or a string (like a tab) to indent with it. This is the entire trick behind any "format JSON" feature:
// Third argument = indentation. A number pads with that many spaces;
// a string uses that string per level.
JSON.stringify(user, null, 2);
/*
{
"name": "Ada",
"langs": [
"JS",
"Rust"
],
"active": true
}
*/
JSON.stringify(user, null, '\t'); // indent with tabs
Use 2 for human-readable output in logs and files; drop the argument entirely for the smallest
possible payload on the wire.
The replacer: filtering and transforming output
The second argument to stringify is a replacer. As an array it acts as a key allow-list;
as a function it's called for every value and lets you transform or drop fields — handy for stripping
secrets before logging:
// replacer: an allow-list of keys, or a function to transform values.
const account = { id: 7, name: 'Ada', password: 'hunter2' };
JSON.stringify(account, ['id', 'name']); // drop everything else
// '{"id":7,"name":"Ada"}'
JSON.stringify(account, (key, value) =>
key === 'password' ? undefined : value, // redact by returning undefined
);
// '{"id":7,"name":"Ada"}' The reviver: post-processing on parse
JSON.parse has a symmetric second argument, the reviver, called for every key/value pair as the
text is parsed. Its classic use is rehydrating values JSON can't natively represent, such as turning ISO date
strings back into Date objects:
// reviver: runs on every key/value as it is parsed — revive Dates, BigInts, etc.
const text = '{"created":"2026-06-22T10:00:00.000Z","count":3}';
const obj = JSON.parse(text, (key, value) =>
key === 'created' ? new Date(value) : value,
);
obj.created instanceof Date; // true What JSON silently drops or changes
JSON is a small format — it has objects, arrays, strings, numbers, booleans and null, and
nothing else. Anything outside that set is either dropped, coerced, or throws on the way out:
const value = {
when: new Date(), // → becomes an ISO string, not a Date
big: 10n, // → THROWS: BigInt can't be serialized
missing: undefined, // → key is dropped entirely
fn: () => 1, // → key is dropped entirely
nan: NaN, // → becomes null
};
// JSON has no Date, no functions, no undefined, no NaN/Infinity.
The two that bite hardest: a Date round-trips to an ISO string (use a reviver to get
the Date back), and a BigInt throws outright — you must convert it to a string
yourself first. Keys whose value is undefined or a function simply vanish from the output, which
is occasionally surprising when a field you expected isn't there.
Debugging "Unexpected token" errors
When JSON.parse throws, the message usually points at the first character it couldn't accept.
The usual culprits, in rough order of frequency: a trailing comma after the last element;
single quotes instead of double; an unquoted key; or a leading character
you didn't expect (a stray ) from a JSONP wrapper, or a UTF-8 byte-order mark). Because JSON is
whitespace-insensitive, a formatter that re-indents the document makes the structural mistake jump out
visually — that's often the fastest way to find it.
Parse defensively
Any time the JSON comes from outside your code — a network response, a file, user input — a single malformed character will throw and can crash a whole request handler. Wrap untrusted parses so a bad string degrades gracefully instead:
function tryParse(text, fallback = null) {
try {
return JSON.parse(text);
} catch {
return fallback; // never let bad input crash the caller
}
} That's the whole API. For a quick visual check — is this valid? where's the broken bracket? — paste it into the JSON formatter; it runs entirely in your browser, so even sensitive payloads never leave the page. If you also need to convert between JSON and other shapes, see the JSON to CSV and YAML to JSON tools.
Try it now: the JSON formatter does everything in this guide in your browser — nothing is uploaded. Browse more guides or the full tool list.