What Is JSON? How to Parse JSON in JavaScript (With Examples)

Muhaymin Bin Mehmood

Muhaymin Bin Mehmood

·
7 min read
Published Dec 12, 2024
Updated Oct 9, 2026
What is JSON, and How Do You Parse It Banner Image
15 min read
1,005 words
22 sections17 code blocks

JSON (JavaScript Object Notation) is a text format for structured data: objects, arrays, strings, numbers, booleans and null. APIs send it, config files use it, and localStorage stores it. In JavaScript you turn JSON text into a value with JSON.parse() and turn a value back into JSON text with JSON.stringify().

Tested with: Node.js 20.20, Chromium 156 and WebKit 27.2 (Safari's engine) via Playwright, October 2026. Every error message below was copied from those runs.

What JSON Looks Like

JSON
{
  "name": "Alice",
  "age": 25,
  "skills": ["js", "css"],
  "admin": false,
  "manager": null,
  "address": { "city": "Lahore", "zip": "54000" }
}
  • Keys must be in double quotes. Strings too: single quotes are not allowed.
  • Values can be a string, number, true/false, null, an object or an array. There is no undefined, no functions, no dates and no comments.
  • No trailing commas after the last item.

JSON vs a JavaScript object

JSONJavaScript object literal
What it isA string (text)A value in memory
KeysAlways "double-quoted"Quotes optional
StringsDouble quotes only' " or `
Trailing commasNot allowedAllowed
CommentsNot allowedAllowed
undefined, functions, Date, MapNot supportedSupported

How to Parse JSON in JavaScript: JSON.parse()

JavaScript
const text = '{"name": "Alice", "age": 25, "skills": ["js", "css"]}';
const user = JSON.parse(text);

console.log(user.name);      // "Alice"
console.log(user.skills[1]); // "css"
console.log(typeof user);    // "object"

JSON.parse throws a SyntaxError if the text isn't valid JSON, so wrap it whenever the input comes from outside your code (users, files, APIs, storage):

JavaScript
// Parse JSON without throwing: returns { ok, value } or { ok: false, error }
export function parseJSON(text) {
  try {
    return { ok: true, value: JSON.parse(text) };
  } catch (error) {
    return { ok: false, error };
  }
}
JavaScript
import { parseJSON } from "./parse-json.js";

const result = parseJSON(input);
if (result.ok) {
  render(result.value);
} else {
  showError("That isn't valid JSON: " + result.error.message);
}

Reference: JSON.parse() on MDN.

JSON.parse error messages by browser

The same mistake gives different messages in each engine. These are from our test runs (Chrome also adds the line and column):

InputChrome / Node.jsSafari (WebKit)
{name: 'Alice'}Expected property name or '}' in JSON at position 1JSON Parse error: Expected '}'
{'name': 'Alice'}Expected property name or '}' in JSON at position 1JSON Parse error: Single quotes (') are not allowed in JSON
{"a": 1,}Expected double-quoted property name in JSON at position 8JSON Parse error: Property name must be a string literal
{"a": 1} // noteUnexpected non-whitespace character after JSON at position 9JSON Parse error: Unrecognized token '/'
"" (empty string)Unexpected end of JSON inputJSON Parse error: Unexpected EOF
<!DOCTYPE html>Unexpected token '<', "<!DOCTYPE html>" is not valid JSONJSON Parse error: Unrecognized token '<'
undefined"undefined" is not valid JSONJSON Parse error: Unexpected identifier "undefined"

The < error almost always means you got an HTML page (a 404, a login page, an error page) instead of JSON. Our Unexpected token guide walks through each cause and fix.

Two surprises: JSON.parse(null) returns null (because null becomes the string "null"), and duplicate keys don't throw, the last one wins: JSON.parse('{"a": 1, "a": 2}') gives { a: 2 }.

JSON.stringify(): Turning Values Into JSON

JavaScript
const user = { name: "Bob", age: 30 };

JSON.stringify(user);
// '{"name":"Bob","age":30}'

JSON.stringify(user, null, 2);
// {
//   "name": "Bob",
//   "age": 30
// }

The third argument indents the output, which is handy for logs and files. Reference: JSON.stringify() on MDN.

What JSON.stringify silently drops or changes

JavaScript
JSON.stringify({
  a: undefined,          // dropped
  f() {},                // dropped
  s: Symbol("x"),        // dropped
  n: NaN,                // null
  i: Infinity,           // null
  d: new Date(0),        // "1970-01-01T00:00:00.000Z"
  m: new Map([["k", 1]]), // {}
  set: new Set([1]),     // {}
  arr: [undefined, () => 1, NaN], // [null, null, null]
});
// '{"n":null,"i":null,"d":"1970-01-01T00:00:00.000Z","m":{},"set":{},"arr":[null,null,null]}'
  • Object properties that are undefined, functions or symbols disappear; inside arrays they become null.
  • NaN and Infinity become null.
  • Dates become ISO strings, and stay strings when you parse them back.
  • Map and Set become empty objects: your data is gone without an error.

Errors JSON.stringify does throw

ValueChrome / Node.jsSafari (WebKit)
{ id: 10n } (BigInt)TypeError: Do not know how to serialize a BigIntTypeError: JSON.stringify cannot serialize BigInt.
An object that references itselfTypeError: Converting circular structure to JSONTypeError: JSON.stringify cannot serialize cyclic structures.

Fixing Map, Set and BigInt with a replacer

JavaScript
// JSON has no Map, Set or BigInt: convert them in a replacer
export function toJSONText(value, space) {
  return JSON.stringify(
    value,
    (key, val) => {
      if (val instanceof Map) return Object.fromEntries(val);
      if (val instanceof Set) return [...val];
      if (typeof val === "bigint") return val.toString();
      return val;
    },
    space
  );
}
JavaScript
toJSONText({ tags: new Set(["js", "react"]), scores: new Map([["ali", 3]]), id: 12345678901234567890n });
// '{"tags":["js","react"],"scores":{"ali":3},"id":"12345678901234567890"}'

For your own classes, add a toJSON() method and JSON.stringify will use its return value:

JavaScript
const order = {
  price: { amount: 5, toJSON() { return "$5.00"; } },
};
JSON.stringify(order); // '{"price":"$5.00"}'

Parsing Dates With a Reviver

The second argument of JSON.parse is a reviver: it sees every key and value and can replace them. This one turns full ISO timestamps back into Date objects and leaves other strings alone:

JavaScript
const ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/;

// A reviver runs for every key/value; return what you want stored instead
export function parseWithDates(text) {
  return JSON.parse(text, (key, value) =>
    typeof value === "string" && ISO_DATE.test(value) ? new Date(value) : value
  );
}
JavaScript
const event = parseWithDates('{"title": "Launch", "at": "2026-10-09T08:30:00.000Z"}');
event.at instanceof Date; // true
event.at.getUTCHours();   // 8

In our test the timestamp became a Date and a plain "2026-10-09" stayed a string, because the pattern only matches full UTC timestamps.

JSON in localStorage

localStorage only stores strings, so you stringify on the way in and parse on the way out. The common one-liner crashes when the key doesn't exist yet:

JavaScript
// Crashes when "user" was never saved:
const storedUser = JSON.parse(localStorage.getItem("user"));
console.log(storedUser.name);
// Chrome: TypeError: Cannot read properties of null (reading 'name')

These two helpers handle a missing key, an old value that isn't JSON, a full storage quota and values that can't be stringified:

JavaScript
// Read and write JSON in localStorage without crashing on
// missing keys, old non-JSON values or a full/blocked storage.
export function readJSON(key, fallback) {
  try {
    const text = localStorage.getItem(key);
    return text === null ? fallback : JSON.parse(text);
  } catch {
    return fallback;
  }
}

export function writeJSON(key, value) {
  try {
    localStorage.setItem(key, JSON.stringify(value));
    return true;
  } catch {
    return false; // quota exceeded, private mode, or a value that can't be stringified
  }
}
JavaScript
import { readJSON, writeJSON } from "./storage.js";

const settings = readJSON("settings", { theme: "light" }); // fallback if missing or broken
settings.theme = "dark";
writeJSON("settings", settings);

In our tests: a missing key and a corrupt value ("dark" saved without JSON) both returned the fallback, and writing a circular object returned false instead of throwing. More in our localStorage and sessionStorage guide.

JSON From an API (fetch)

response.json() parses the body for you, but when the server sends HTML its error is unhelpful, especially in Safari:

Engineresponse.json() on an HTML page
Chrome / Node.jsSyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Safari (WebKit)SyntaxError: The string did not match the expected pattern.

Reading the body as text first lets you show what actually came back:

JavaScript
// Read the body as text first, so a bad response gives a useful error
export async function getJSON(url, options) {
  const res = await fetch(url, options);
  const text = await res.text();
  if (!res.ok) {
    throw new Error(`HTTP ${res.status}: ${text.slice(0, 100)}`);
  }
  try {
    return JSON.parse(text);
  } catch {
    throw new Error(`Expected JSON from ${url}, got: ${text.slice(0, 100)}`);
  }
}

In our tests this returned the data for a JSON response, HTTP 500: {"error":"Database unavailable"} for a server error, and Expected JSON from …/html, got: <!DOCTYPE html>… for an HTML page, in all three engines. See our Fetch API guide for the rest of fetch.

Big Numbers Lose Precision

JavaScript
JSON.parse('{"id": 12345678901234567890}').id;
// 12345678901234567000  ← the last digits changed

JavaScript numbers are 64-bit floats, so integers above Number.MAX_SAFE_INTEGER (9,007,199,254,740,991) get rounded during parsing. If an API sends large IDs, ask for them as strings (many APIs, like Twitter/X, include an id_str field for this reason).

Deep Copy: JSON vs structuredClone

JavaScript
const original = { when: new Date(0) };

typeof JSON.parse(JSON.stringify(original)).when; // "string"
structuredClone(original).when instanceof Date;   // true

JSON.parse(JSON.stringify(obj)) is an old deep-copy trick, but it turns dates into strings and drops everything in the lossy list above. structuredClone() (all modern browsers and Node.js 17+) keeps dates, Maps, Sets and circular references.

Large JSON Files

  • In the browser, rendering is usually the bottleneck, not parsing: see optimizing large JSON rendering in React.
  • In Node.js, reading a huge file and calling JSON.parse on it loads everything into memory. Use newline-delimited JSON (one object per line) and read it as a stream, or a streaming JSON parser. If you're already hitting memory limits, see fixing JavaScript heap out of memory.
  • For real-time data, JSON messages over a WebSocket are parsed one message at a time.

Security

  • JSON.parse never runs code, so it's safe to call on untrusted text. Never use eval() to parse JSON.
  • Validate the shape of parsed data before trusting it (required fields, types). Libraries like Zod help.
  • Be careful copying parsed objects into other objects with a deep merge: a "__proto__" key in untrusted JSON can lead to prototype pollution in naive merge code.

FAQs

What is JSON used for?

Sending data between a browser and a server (APIs), configuration files like package.json, storing data in localStorage, and messages between services.

How do I parse JSON in JavaScript?

Call JSON.parse(text). It returns the object or array the text describes and throws a SyntaxError if the text isn't valid JSON, so wrap it in try/catch for outside input.

What's the difference between JSON.parse and JSON.stringify?

JSON.parse turns JSON text into a JavaScript value. JSON.stringify turns a JavaScript value into JSON text.

Why does JSON.parse say "Unexpected token"?

The text isn't JSON. The most common cause is an HTML page (starting with <) returned instead of JSON; others are single quotes, trailing commas or an empty string. See the error table above.

Can JSON have comments?

No. JSON.parse rejects them. Some tools accept a JSON-with-comments variant (like tsconfig.json), but that isn't standard JSON.

Is JSON the same as a JavaScript object?

No. JSON is text with stricter rules. A JavaScript object is a value in memory. You convert between them with JSON.parse and JSON.stringify.

No comments yet. Be the first to comment!

Leave a Comment

2000 characters remaining

Related Articles

View all
Muhaymin Bin Mehmood

About Muhaymin Bin Mehmood

Front-end Developer skilled in the MERN stack, experienced in web and mobile development. Proficient in React.js, Node.js, and Express.js, with a focus on client interactions, sales support, and high-performance applications.