JSON.stringify() vs JSON.parse() — Complete Difference Guide
JSON.stringify() and JSON.parse() are the two most important JSON methods in JavaScript. One converts objects to strings; the other converts strings back to objects. Understanding both — including their edge cases and gotchas — is essential for every developer working with APIs, localStorage, or any data exchange.
Object→String
JSON.stringify() direction
String→Object
JSON.parse() direction
Serialization
what stringify is called
Deserialization
what parse is called
The Core Difference
These two methods are inverse operations. JSON.stringify() converts a JavaScript value (object, array, primitive) into a JSON-formatted string. JSON.parse() takes a JSON string and converts it back into a JavaScript value. They form a complete serialization cycle.
Quick fact
JSON stands for JavaScript Object Notation. Despite the name, JSON is a language-independent format used across Python, Java, Ruby, Go, and virtually every other programming language.
JSON.stringify() — Object to String
Use JSON.stringify() whenever you need to convert a JavaScript value into a string for transmission or storage: sending to an API, saving in localStorage, writing to a file, or logging objects as readable text.
const user = { name: "Alice", age: 30, active: true };
// Basic stringify
const json = JSON.stringify(user);
console.log(json);
// → '{"name":"Alice","age":30,"active":true}'
console.log(typeof json);
// → 'string'
// With indentation (pretty print)
const pretty = JSON.stringify(user, null, 2);
console.log(pretty);
// → {
// "name": "Alice",
// "age": 30,
// "active": true
// }
// Arrays work too
const items = [1, "hello", true, null];
console.log(JSON.stringify(items));
// → '[1,"hello",true,null]'The replacer parameter
const data = {
id: 1,
name: "Alice",
password: "secret123", // we want to exclude this
createdAt: new Date("2024-01-01"),
};
// Array replacer: only include these keys
const safe = JSON.stringify(data, ["id", "name"]);
console.log(safe);
// → '{"id":1,"name":"Alice"}'
// Function replacer: custom logic
const result = JSON.stringify(data, (key, value) => {
if (key === "password") return undefined; // exclude
if (value instanceof Date) return value.toISOString(); // transform
return value;
});
console.log(result);
// → '{"id":1,"name":"Alice","createdAt":"2024-01-01T00:00:00.000Z"}'
// Third argument: indentation (2 or 4 spaces, or a string like " ")
console.log(JSON.stringify({ a: 1 }, null, 4));
// → {
// "a": 1
// }JSON.parse() — String to Object
Use JSON.parse() whenever you receive a JSON string and need to work with it as a JavaScript value: reading from an API response, loading from localStorage, or parsing JSON files.
const jsonString = '{"name":"Bob","age":25,"tags":["js","react"]}';
// Basic parse
const obj = JSON.parse(jsonString);
console.log(obj.name); // → 'Bob'
console.log(obj.tags[0]); // → 'js'
console.log(typeof obj); // → 'object'
// Parse numbers and booleans
const config = JSON.parse('{"debug":true,"maxRetries":3,"timeout":5000}');
console.log(config.debug); // → true (boolean, not string)
console.log(config.maxRetries); // → 3 (number, not string)
// Parse arrays
const ids = JSON.parse('[1, 2, 3, 4, 5]');
console.log(ids.length); // → 5// The reviver runs on every parsed key-value pair
const json = '{"name":"Alice","createdAt":"2024-01-15T10:30:00.000Z","score":95}';
const data = JSON.parse(json, (key, value) => {
// Convert date strings back to Date objects
if (key === "createdAt") return new Date(value);
return value;
});
console.log(data.createdAt instanceof Date); // → true
console.log(data.createdAt.getFullYear()); // → 2024Error Handling — Never Skip Try-Catch
JSON.parse() throws a SyntaxError if the string is not valid JSON. In production code, always wrap it in a try-catch. JSON.stringify() can also throw for circular references.
// No error handling — crashes on invalid JSON
function loadConfig(jsonStr) {
return JSON.parse(jsonStr); // throws SyntaxError if invalid
}
// Calling with malformed JSON
loadConfig("{broken json,}"); // Uncaught SyntaxError!// Always wrap JSON.parse in try-catch
function safeParseJSON(jsonStr, fallback = null) {
try {
return JSON.parse(jsonStr);
} catch (error) {
console.error('JSON parse failed:', error.message);
return fallback;
}
}
// Safe — returns null instead of throwing
const result = safeParseJSON("{broken}", null);
console.log(result); // → null// Circular reference causes TypeError
const obj = { name: "Alice" };
obj.self = obj; // circular!
// This throws: TypeError: Converting circular structure to JSON
// JSON.stringify(obj);
// Solution 1: Remove circular references before stringify
const { self, ...safeObj } = obj;
console.log(JSON.stringify(safeObj)); // → '{"name":"Alice"}'
// Solution 2: Use a library like flatted or json-stringify-safe
// import { stringify } from 'flatted';
// console.log(stringify(obj)); // handles circular refsWhat Gets Lost in Stringify
JSON only supports a subset of JavaScript types. Several things are silently dropped or transformed when you stringify an object. This is a very common source of bugs.
Types lost during JSON.stringify()
const data = {
name: "Alice",
fn: () => "hello", // function → omitted
sym: Symbol("id"), // Symbol → omitted
undef: undefined, // undefined → omitted
date: new Date("2024-01-01"), // Date → ISO string
nan: NaN, // NaN → null
inf: Infinity, // Infinity → null
map: new Map([["a", 1]]), // Map → {} (empty object!)
set: new Set([1, 2, 3]), // Set → {} (empty object!)
};
const json = JSON.stringify(data);
const parsed = JSON.parse(json);
console.log(parsed);
// → {
// name: "Alice",
// date: "2024-01-01T00:00:00.000Z", // string, not Date!
// nan: null,
// inf: null,
// map: {}, // lost all data!
// set: {}, // lost all data!
// }
// fn, sym, undef are completely gone!Common Use Cases with Code
// Sending JSON to an API
async function createUser(userData) {
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userData), // ← stringify for transmission
});
if (!response.ok) throw new Error('Request failed');
const newUser = await response.json(); // ← response.json() calls JSON.parse internally
return newUser;
}
const user = await createUser({ name: "Carol", email: "carol@example.com" });// Save object to localStorage
function saveSettings(settings) {
localStorage.setItem('app-settings', JSON.stringify(settings));
}
// Load object from localStorage
function loadSettings(defaults = {}) {
const stored = localStorage.getItem('app-settings');
if (!stored) return defaults;
try {
return JSON.parse(stored);
} catch {
return defaults;
}
}
saveSettings({ theme: 'dark', fontSize: 14 });
const settings = loadSettings({ theme: 'light', fontSize: 12 });
console.log(settings.theme); // → 'dark'// Quick deep clone using stringify + parse
// WARNING: only works for JSON-safe values (no functions, Dates, etc.)
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
const original = { user: { name: "Dave", scores: [10, 20, 30] } };
const clone = deepClone(original);
clone.user.name = "Eve";
clone.user.scores.push(40);
console.log(original.user.name); // → 'Dave' (unchanged)
console.log(original.user.scores); // → [10, 20, 30] (unchanged)
// For production: use structuredClone() instead (handles Dates, Maps, etc.)Performance Considerations
JSON.stringify is expensive for large objects
For deeply nested or large objects (thousands of keys), stringify can be a bottleneck. Profile before optimizing — usually it's not the bottleneck.
JSON.parse is generally fast
V8 and other engines have heavily optimized JSON.parse. For most use cases, parsing even large JSON strings is very fast.
Avoid parsing the same string multiple times
If you need to read a JSON string multiple times, parse it once and reuse the object. Parsing is idempotent but not free.
Use streaming parsers for huge data
For files or API responses over several MB, use streaming JSON parsers (like node-JSONStream) instead of parsing the entire string at once.
Quick Reference
// ═══════════════════════════════════════════
// JSON.stringify() — JavaScript → JSON string
// ═══════════════════════════════════════════
JSON.stringify(value) // basic
JSON.stringify(value, null, 2) // pretty print (2 spaces)
JSON.stringify(value, ["key1"]) // only include these keys
JSON.stringify(value, replacerFn) // custom transform
// ════════════════════════════════════════════
// JSON.parse() — JSON string → JavaScript value
// ════════════════════════════════════════════
JSON.parse(jsonString) // basic
JSON.parse(jsonString, reviverFn) // with type transformation
// ═══════════════════
// ALWAYS use try-catch
// ═══════════════════
try {
const data = JSON.parse(maybeJson);
} catch (e) {
// handle invalid JSON
}
// ════════════════════════════════════════════════
// What JSON supports:
// string, number, boolean, null, object, array
//
// What JSON does NOT support:
// undefined, function, Symbol, Date, NaN, Infinity
// Map, Set, BigInt
// ════════════════════════════════════════════════Frequently Asked Questions
Need to work with JSON data? Try our free JSON Parser and Beautifier and JSON.stringify() online tool.