HomeBlog › JSON.stringify and JSON.parse

JSON.stringify and JSON.parse: The Complete Guide

Published March 5, 2026 • 10 min read

Every JavaScript developer uses JSON.stringify and JSON.parse daily, but few know all their options. This guide covers everything from basic usage to replacers, revivers, circular references, and performance.

JSON.stringify — Basic Usage

const user = { name: "Alice", age: 30, active: true };
JSON.stringify(user);
// '{"name":"Alice","age":30,"active":true}'

Pretty-printing with indentation

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

JSON.stringify(user, null, '\t'); // Tab indentation

What JSON.stringify omits

These values are omitted or converted during serialization:

const obj = {
  fn: () => {},        // omitted (functions)
  sym: Symbol('x'),   // omitted (symbols)
  undef: undefined,   // omitted (undefined)
  nan: NaN,           // becomes null
  inf: Infinity,      // becomes null
  date: new Date(),   // becomes ISO string
  regex: /abc/        // becomes {}
};
JSON.stringify(obj);
// '{"nan":null,"inf":null,"date":"2026-03-05T10:00:00.000Z","regex":{}}'

The Replacer Argument

The second argument to JSON.stringify is a replacer — either an array of allowed keys, or a function.

Array replacer — whitelist specific keys

const user = { id: 1, name: "Alice", password: "secret", email: "a@b.com" };
JSON.stringify(user, ['id', 'name']);
// '{"id":1,"name":"Alice"}'  — password excluded

Function replacer — transform values

JSON.stringify(user, (key, value) => {
  if (key === 'password') return undefined; // exclude
  if (typeof value === 'number') return value * 2; // transform
  return value;
});

Custom toJSON method

class Money {
  constructor(amount, currency) {
    this.amount = amount;
    this.currency = currency;
  }
  toJSON() {
    return `${this.amount} ${this.currency}`;
  }
}
JSON.stringify(new Money(42, 'USD')); // '"42 USD"'

JSON.parse — Basic Usage

const jsonString = '{"name":"Alice","age":30}';
const user = JSON.parse(jsonString);
console.log(user.name); // "Alice"

Always use try-catch

function safeParseJSON(str) {
  try {
    return { data: JSON.parse(str), error: null };
  } catch (e) {
    return { data: null, error: e.message };
  }
}

const { data, error } = safeParseJSON(userInput);
if (error) {
  console.error('Invalid JSON:', error);
}

Reviver — transform values on parse

const json = '{"name":"Alice","createdAt":"2026-03-05T10:00:00.000Z"}';

const obj = JSON.parse(json, (key, value) => {
  // Revive ISO date strings back to Date objects
  if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
    return new Date(value);
  }
  return value;
});

console.log(obj.createdAt instanceof Date); // true

Handling Circular References

const a = {};
a.self = a; // circular reference
JSON.stringify(a); // TypeError: Converting circular structure to JSON

Fix using a WeakSet to track seen objects:

function safeStringify(obj) {
  const seen = new WeakSet();
  return JSON.stringify(obj, (key, value) => {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) return '[Circular]';
      seen.add(value);
    }
    return value;
  });
}
safeStringify(a); // '{"self":"[Circular]"}'

Deep Clone with JSON

A common pattern for deep cloning simple objects:

const original = { a: 1, b: { c: 2 } };
const clone = JSON.parse(JSON.stringify(original));
clone.b.c = 99;
console.log(original.b.c); // 2 — original unchanged

Limitation: This does not clone functions, Dates (loses Date object, gets string), undefined values, symbols, or handle circular references. For production deep cloning, use structuredClone() instead.

// Better: structuredClone (modern browsers + Node 17+)
const clone = structuredClone(original);

Performance Tips

Frequently Asked Questions

What is the difference between JSON.stringify and toString?

toString() on an object returns [object Object] — not useful. JSON.stringify() serializes the full structure of the object to a JSON string. Always use JSON.stringify() for data serialization.

Does JSON.parse validate the JSON?

Yes — JSON.parse() throws a SyntaxError if the string is not valid JSON. This is why wrapping it in try-catch is essential when parsing untrusted input. For detailed error information (line/column), use the JSON Validator tool.

Can JSON.stringify handle BigInt?

No. JSON.stringify(BigInt(9007199254740993)) throws a TypeError: Do not know how to serialize a BigInt. Use a replacer to convert BigInt to string: (key, val) => typeof val === 'bigint' ? val.toString() : val.

Validate and format your JSON

Free online JSON validator, formatter, and 65+ more tools.

Also read: JSON Schema Tutorial | JSON vs XML | JSON Cheat Sheet | JSON Formatter

JSON.stringify() Options Reference

// Syntax: JSON.stringify(value, replacer, space)

// Basic
JSON.stringify({name: "Alice", age: 30})
// '{"name":"Alice","age":30}'

// Pretty print (2-space indent)
JSON.stringify({name: "Alice"}, null, 2)
// '{\n  "name": "Alice"\n}'

// Replacer array (include only specified keys)
JSON.stringify({name: "Alice", password: "secret", age: 30}, ["name", "age"])
// '{"name":"Alice","age":30}'

// Replacer function (custom filtering/transform)
JSON.stringify({a: 1, b: undefined, c: null}, (key, value) => {
  if (value === undefined) return undefined; // exclude undefined
  return value;
})

// toJSON() method (custom serialization)
const date = new Date('2024-01-01');
JSON.stringify({date}) // '{"date":"2024-01-01T00:00:00.000Z"}'

JSON.parse() Options Reference

// Syntax: JSON.parse(text, reviver)

// Basic
const obj = JSON.parse('{"name":"Alice","age":30}');

// With reviver (transform values during parse)
const data = JSON.parse('{"date":"2024-01-01","score":"42"}', (key, value) => {
  if (key === 'date') return new Date(value); // restore Date objects
  if (key === 'score') return parseInt(value); // convert string to number
  return value;
});

// Error handling (always use try/catch)
try {
  const parsed = JSON.parse(possiblyInvalidJson);
} catch (err) {
  console.error('Invalid JSON:', err.message);
}

JSON.stringify vs JSON.parse: Common Gotchas

Gotcha Problem Solution
undefined valuesJSON.stringify omits themUse replacer to convert to null
Date objectsSerialized as ISO stringsUse reviver in JSON.parse to restore
Circular referencesJSON.stringify throwsUse a library like flatted or circular-json
BigIntJSON.stringify throwsUse replacer: (k,v) => typeof v === 'bigint' ? v.toString() : v
NaN / InfinitySerialized as nullHandle before stringifying
Prototype methodsNot serializedOnly own enumerable properties are included

JSON Stringify and Parse: Complete Guide

JSON.stringify() and JSON.parse() are the two core functions for working with JSON in JavaScript. Together they serialize objects to strings and deserialize strings back to objects.

Stringify → Parse Round-Trip

const user = {
  id: 1,
  name: "Alice",
  createdAt: new Date("2024-01-01"),
  active: true
};

// Stringify
const json = JSON.stringify(user);
// '{"id":1,"name":"Alice","createdAt":"2024-01-01T00:00:00.000Z","active":true}'

// Parse
const parsed = JSON.parse(json);
console.log(parsed.id);   // 1
console.log(parsed.name); // "Alice"
console.log(typeof parsed.createdAt); // "string" (Date becomes string!)

Reviver Function: Restoring Date Objects

const reviver = (key, value) => {
  // Convert ISO date strings back to Date objects
  if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
    return new Date(value);
  }
  return value;
};

const parsed = JSON.parse(json, reviver);
console.log(parsed.createdAt instanceof Date); // true

Deep Clone with JSON

// Simple deep clone (lossy — loses Date, Function, undefined)
const clone = JSON.parse(JSON.stringify(original));

// Better: structuredClone (preserves Date, Map, Set)
const clone = structuredClone(original);

Error Handling

// Always wrap parse in try/catch
try {
  const data = JSON.parse(userInput);
  // use data safely
} catch (e) {
  console.error("Invalid JSON:", e.message);
  // handle gracefully
}