Working with JSON in JavaScript

A practical cookbook for JavaScript developers — parse and stringify values, fetch JSON from an API, persist it in localStorage, and sidestep the gotchas.

JSON is the lingua franca of the web, and JavaScript gives you a tiny but powerful built-in JSON object for working with it. This guide walks through the everyday tasks you will hit in real projects: turning strings into objects and back again, loading JSON over the network, saving it between page loads, formatting it for humans, iterating over it, and avoiding the surprises that bite even experienced developers.

Parsing and stringifying

The two methods you will use most are JSON.parse(), which turns a JSON string into a JavaScript value, and JSON.stringify(), which turns a JavaScript value back into a JSON string. They are exact mirror images of each other.

// String -> value
const user = JSON.parse('{"name":"Ada","age":36}');
user.name; // "Ada"

// Value -> string
const text = JSON.stringify({ name: 'Ada', age: 36 });
text; // '{"name":"Ada","age":36}'

Parsing has more depth than it first appears — the reviver argument, error handling, and equivalents in other languages. For a full breakdown, read our JSON.parse() guide.

Fetching JSON from an API

Most JSON you handle arrives over the network. The fetch() API returns a response object, and calling res.json() reads the body and parses it for you — no manual JSON.parse() needed.

async function getUser(id) {
  const res = await fetch(`/api/users/${id}`);

  if (!res.ok) {
    throw new Error(`Request failed: ${res.status}`);
  }

  const user = await res.json();
  return user;
}

Always check res.ok before reading the body. fetch() only rejects on network failures — a 404 or 500 still resolves successfully, so an error page can sneak through as if it were valid data.

Storing JSON in localStorage

localStorage can only hold strings, so you stringify on the way in and parse on the way out. This pattern is perfect for caching settings, drafts, or small bits of state between visits.

// Save: value -> string
const settings = { theme: 'dark', fontSize: 14 };
localStorage.setItem('settings', JSON.stringify(settings));

// Read: string -> value
const saved = JSON.parse(localStorage.getItem('settings'));
saved.theme; // "dark"

If the key has never been set, getItem() returns null, and JSON.parse(null) happens to yield null rather than throwing — but it is safer to guard for a missing value before parsing.

Pretty-printing JSON

By default JSON.stringify() produces a single compact line. Pass a third argument — the indentation — to get readable, multi-line output for logs, files, or debugging.

const data = { name: 'Ada', roles: ['admin', 'editor'] };

JSON.stringify(data, null, 2);
// {
//   "name": "Ada",
//   "roles": [
//     "admin",
//     "editor"
//   ]
// }

The second argument is a replacer (often null) and the third is the number of spaces per level. You can pass '\t' instead of a number to indent with tabs.

Looping over JSON data

Once a JSON string is parsed, it is just an ordinary object or array — so you iterate with the same tools you already use. For objects, Object.entries() gives you key/value pairs:

const scores = JSON.parse('{"ada":91,"linus":88}');

for (const [name, score] of Object.entries(scores)) {
  console.log(`${name}: ${score}`);
}
// ada: 91
// linus: 88

For arrays of records, map() is the idiomatic way to transform each item:

const users = JSON.parse('[{"name":"Ada"},{"name":"Linus"}]');

const names = users.map((user) => user.name);
names; // ["Ada", "Linus"]

Common gotchas

JSON is a subset of JavaScript, so some values survive the round trip and some quietly do not. Watch out for these:

  • undefined and functions disappear. JSON.stringify() drops object properties whose value is undefined or a function, and turns them into null inside arrays.
  • Dates become strings. A Date is serialized to an ISO string, and parsing it back gives you a string — not a Date. Use a reviver to restore it.
  • Circular references throw. If an object references itself (directly or through a chain), JSON.stringify() throws a TypeError about a circular structure.
  • NaN and Infinity become null. These non-finite numbers cannot be represented in JSON, so they are stringified as null.

Format and validate your JSON instantly

Working with an API response or a localStorage blob? Paste it into our free formatter to pretty-print it, validate the structure, and catch errors before JSON.parse() ever throws.

Open JSON Formatter