JavaScript JSON: parse, stringify and Working with JSON Data
Learn JSON in JavaScript: JSON.parse, JSON.stringify, replacers, revivers, errors, localStorage and API data, with real examples and common mistakes.
What you will learn
Every time you log in to a website, load a list of products, or save a setting, data travels between your browser and a server. That data is sent as text, and the most popular format for it is JSON. In this lesson you will learn what JSON is, how it differs from a JavaScript object, how to convert in both directions with JSON.stringify and JSON.parse, how to handle errors, how to customise the result with replacers and revivers, and how JSON is used in real projects such as localStorage and APIs.
Want to check or beautify a piece of JSON while you learn? Use the free JSON Formatter tool. Paste your text and it will format it and show you if there is a mistake.
What is JSON?
JSON stands for JavaScript Object Notation. It is a text format for storing and sending data. It looks like a JavaScript object, but it is only a string that follows strict rules.
{
"name": "Riya",
"age": 22,
"isStudent": true,
"skills": ["HTML", "CSS", "JS"],
"address": { "city": "Delhi" },
"nickname": null
}
Why is JSON so popular?
- It is easy to read for humans.
- It is small and simple for computers.
- Every language (JavaScript, Python, Java, PHP…) can read and write it.
The rules of JSON
JSON is stricter than a JavaScript object:
| Rule | JavaScript object | Valid JSON |
|---|---|---|
| Keys | name or "name" |
Must be in double quotes: "name" |
| Text values | 'hi', "hi" or `hi` |
Only double quotes: "hi" |
| Trailing comma | Allowed | Not allowed |
| Comments | Allowed | Not allowed |
Functions, undefined, Symbol |
Allowed | Not allowed |
The allowed JSON value types are: string, number, boolean, null, array and object. Nothing else.
Remember: a JavaScript object lives inside your program. JSON is text that you send, save or receive. To move between the two, you convert.
The two methods
| Method | Direction | Example |
|---|---|---|
JSON.stringify(value) |
JavaScript value to JSON text | object to string |
JSON.parse(text) |
JSON text to JavaScript value | string to object |
Easy way to remember: stringify makes a string. parse reads (parses) the string back into data.
JSON.stringify: object to text
const user = { name: "Riya", age: 22, skills: ["HTML", "CSS"] };
const text = JSON.stringify(user);
console.log(text); // {"name":"Riya","age":22,"skills":["HTML","CSS"]}
console.log(typeof text); // "string"
It works with arrays, text, numbers and booleans too:
console.log(JSON.stringify([1, 2, 3])); // "[1,2,3]"
console.log(JSON.stringify("hello")); // "\"hello\"" (quotes are part of the text)
console.log(JSON.stringify(42)); // "42"
console.log(JSON.stringify(true)); // "true"
console.log(JSON.stringify(null)); // "null"
Pretty printing with the third argument
The third argument adds spaces so the output is easy to read:
const user = { name: "Riya", address: { city: "Delhi" } };
console.log(JSON.stringify(user, null, 2));
Output:
{
"name": "Riya",
"address": {
"city": "Delhi"
}
}
The null in the middle is the “replacer” (you will learn it below). The 2 means “indent with 2 spaces”. You can also pass a text such as "\t" to indent with tabs.
What stringify does with special values
Not everything can become JSON. Here is what happens:
const data = {
name: "Riya",
greet() { return "hi"; }, // function: skipped
secret: undefined, // undefined: skipped
id: Symbol("id"), // symbol: skipped
score: NaN, // NaN becomes null
limit: Infinity, // Infinity becomes null
joined: new Date(Date.UTC(2026, 9, 2)) // Date becomes an ISO text
};
console.log(JSON.stringify(data));
// {"name":"Riya","score":null,"limit":null,"joined":"2026-10-02T00:00:00.000Z"}
Inside arrays, those same values become null (to keep the positions):
console.log(JSON.stringify([1, undefined, function () {}, 4]));
// [1,null,null,4]
More things to know:
- A
Mapor aSetbecomes{}(empty). Convert them first withObject.fromEntries(map)or[...set]. - A BigInt throws a
TypeError. - A circular reference (an object that points back to itself) throws a
TypeError.
const a = { name: "A" };
a.self = a;
try {
JSON.stringify(a);
} catch (error) {
console.log(error.name); // "TypeError" (circular structure)
}
Choosing properties: the replacer
The second argument lets you filter or change what goes into the JSON.
As an array: list the property names you want to keep.
const user = { name: "Riya", age: 22, password: "secret123" };
console.log(JSON.stringify(user, ["name", "age"]));
// {"name":"Riya","age":22}
As a function: it runs for every key and value. Return the value to keep, or undefined to remove it.
const user = { name: "Riya", password: "secret123", age: 22 };
const safe = JSON.stringify(user, (key, value) => {
if (key === "password") return undefined; // remove it
return value;
});
console.log(safe); // {"name":"Riya","age":22}
Custom output with toJSON
If an object has a toJSON method, stringify uses its result. This is how Date becomes text.
const product = {
title: "Pen",
price: 10,
internalCode: "X-99",
toJSON() {
return { title: this.title, price: this.price }; // hide internalCode
}
};
console.log(JSON.stringify(product)); // {"title":"Pen","price":10}
JSON.parse: text to object
const text = '{"name":"Riya","age":22,"skills":["HTML","CSS"]}';
const user = JSON.parse(text);
console.log(user.name); // "Riya"
console.log(user.skills[1]); // "CSS"
console.log(typeof user); // "object"
It can also parse simple values:
console.log(JSON.parse("42")); // 42
console.log(JSON.parse("true")); // true
console.log(JSON.parse("null")); // null
console.log(JSON.parse("[1, 2, 3]")); // [1, 2, 3]
console.log(JSON.parse('"hello"')); // "hello"
Note the quotes: the JSON text for the word hello is "hello" with double quotes inside.
Invalid JSON throws an error
If the text is not valid JSON, JSON.parse throws a SyntaxError. Here are the usual reasons:
// All of these throw SyntaxError:
// JSON.parse("{ name: 'Riya' }"); // keys and text need double quotes
// JSON.parse("{'name': 'Riya'}"); // single quotes not allowed
// JSON.parse('{"name": "Riya",}'); // trailing comma
// JSON.parse(""); // empty text
// JSON.parse(undefined); // becomes the text "undefined"
// JSON.parse('{"a": undefined}'); // undefined is not valid JSON
So always protect parsing of data you do not control with try...catch:
function safeParse(text, fallback = null) {
try {
return JSON.parse(text);
} catch (error) {
console.log("Invalid JSON:", error.name);
return fallback;
}
}
console.log(safeParse('{"ok": true}')); // { ok: true }
console.log(safeParse("{ broken json", {})); // {}
Tip: if you cannot find the mistake in a big JSON text, paste it in the JSON Formatter. It points to the problem.
Changing values while parsing: the reviver
JSON.parse has an optional second argument, a reviver function. It runs for each key and value, and lets you transform the result.
JSON has no date type, so dates come back as text. A reviver can turn them into real Date objects:
const text = '{"title":"Post","published":"2026-10-02T00:00:00.000Z"}';
const post = JSON.parse(text, (key, value) => {
if (key === "published") return new Date(value);
return value;
});
console.log(post.published instanceof Date); // true
console.log(post.published.getUTCFullYear()); // 2026
The round trip
Saving and loading is just stringify then parse:
const original = { name: "Riya", scores: [90, 85] };
const text = JSON.stringify(original); // save this
const restored = JSON.parse(text); // load it back
console.log(restored); // { name: "Riya", scores: [90, 85] }
console.log(restored === original); // false (it is a new object)
What does not survive the round trip: functions, undefined, Symbol, Date objects (they come back as text), Map and Set, and class methods. Keep that in mind.
Real-life use cases
1. Saving data in localStorage
localStorage can store only text, so JSON is the perfect partner:
const settings = { theme: "dark", fontSize: 18 };
localStorage.setItem("settings", JSON.stringify(settings));
const saved = JSON.parse(localStorage.getItem("settings"));
console.log(saved.theme); // "dark"
A safe version that handles missing or broken data:
function loadSettings() {
try {
const raw = localStorage.getItem("settings");
return raw ? JSON.parse(raw) : { theme: "light", fontSize: 16 };
} catch {
return { theme: "light", fontSize: 16 };
}
}
console.log(loadSettings());
2. Reading data from an API
Most APIs reply in JSON. fetch has a helper response.json() that does the parsing for you (you will learn fetch and async/await later in the course):
// You will understand this fully in the Fetch API lesson
async function loadUser() {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const user = await response.json(); // JSON text to object
console.log(user.name);
}
loadUser();
To send data, do the reverse with stringify:
// fetch("/api/users", {
// method: "POST",
// headers: { "Content-Type": "application/json" },
// body: JSON.stringify({ name: "Riya", age: 22 })
// });
3. A quick deep copy (for plain data only)
const original = { name: "Riya", address: { city: "Delhi" } };
const copy = JSON.parse(JSON.stringify(original));
copy.address.city = "Mumbai";
console.log(original.address.city); // "Delhi" (safe)
This works for plain data only. If your data has dates, functions, undefined, Map or Set, use structuredClone(original) instead.
4. Hiding private fields before sending data
const user = { id: 1, name: "Riya", password: "secret", token: "abc" };
const publicData = JSON.stringify(user, (key, value) =>
key === "password" || key === "token" ? undefined : value
);
console.log(publicData); // {"id":1,"name":"Riya"}
5. Converting a Map to JSON and back
const prices = new Map([["pen", 10], ["book", 120]]);
const text = JSON.stringify([...prices]);
console.log(text); // [["pen",10],["book",120]]
const restored = new Map(JSON.parse(text));
console.log(restored.get("book")); // 120
6. A configuration file as a string
const configText = `{
"appName": "MyCodeNest",
"version": 2,
"features": { "darkMode": true, "comments": false }
}`;
const config = JSON.parse(configText);
console.log(config.appName); // "MyCodeNest"
console.log(config.features.darkMode); // true
7. Comparing two simple objects
const a = { x: 1, y: 2 };
const b = { x: 1, y: 2 };
console.log(a === b); // false
console.log(JSON.stringify(a) === JSON.stringify(b)); // true
This works only when the keys are in the same order. For a serious comparison, compare property by property.
8. A readable log of an object
const order = { id: 101, items: [{ name: "Pen", qty: 2 }], paid: true };
console.log(JSON.stringify(order, null, 2));
9. Sorting out an array of JSON records
const json = `[
{ "name": "Riya", "score": 82 },
{ "name": "Karan", "score": 67 },
{ "name": "Neha", "score": 91 }
]`;
const students = JSON.parse(json);
const top = students
.filter((s) => s.score >= 80)
.map((s) => s.name);
console.log(top); // ["Riya", "Neha"]
Common mistakes
- Using single quotes or unquoted keys in JSON. Only
"double quotes"are valid:{"name":"Riya"}. - Leaving a trailing comma at the end of an object or array.
- Forgetting that
JSON.parseneeds a string.JSON.parse(obj)on an object turns it into"[object Object]"and fails. - Calling
JSON.parseon data you do not control withouttry...catch. One broken string can stop your whole program. - Thinking JSON is a JavaScript object. JSON is text. After
stringify, you cannot use.nameon it. You mustparseit first. - Expecting functions,
undefined,Map,Setor class methods to survive. They are dropped or changed. - Expecting dates to come back as dates. They come back as text. Use a reviver or
new Date(text). - Parsing the same data twice (
JSON.parse(JSON.parse(x))) or stringifying twice. You end up with text inside text. - Using the JSON trick for deep copies of complex data. Use
structuredClone. - Storing secrets in
localStorageJSON. Anyone using the browser can read it.
Practice
- Create an object with
name,age, an arrayhobbiesand a nestedaddress. Convert it to JSON text and print it. Printtypeofof the result. - Print the same object pretty-printed with 2 spaces of indentation.
- Parse the text
'{"city":"Delhi","pin":110001}'and print the city. - Write
safeParse(text)that returnsnullinstead of crashing when the text is not valid JSON. Test it with"{ bad json". - Create an object with a
password. Use a replacer so thatJSON.stringifyremoves it. - Show what happens to
{ a: undefined, b: () => 1, c: NaN, d: new Date(0) }afterJSON.stringify. - Save a
todosarray inlocalStorageand load it back in a second step. - Use a reviver to turn a
"created"text into aDateobject while parsing. - Make a deep copy using
JSON.parse(JSON.stringify(...)), then try the same withstructuredClone, and name one case where the JSON trick fails. - Challenge: paste a JSON text with one deliberate mistake into the JSON Formatter, find the problem, and then write the corrected version in your code.
Recap
- JSON is a text format for data. It has strict rules: double quotes for keys and text, no trailing commas, no comments, and only string, number, boolean,
null, array and object values. JSON.stringify(value)turns a JavaScript value into JSON text. UseJSON.stringify(value, null, 2)for readable output.JSON.parse(text)turns JSON text back into a value. Invalid JSON throws aSyntaxError, so wrap data you do not control intry...catch.stringifydrops functions,undefinedand symbols, turnsNaN/Infinityintonull, turns dates into ISO text, and fails on circular references and BigInt.- A replacer (array or function) filters or changes the output. A reviver changes values while parsing.
toJSON()controls how an object is converted. - JSON is used everywhere:
localStorage, API requests and responses, config files, and quick copies of plain data. - Use the JSON Formatter to format, read and debug JSON.
- Next you will learn dates and time: how to create, read, format and calculate with the
Dateobject.