Menu

JSON in JavaScript: JSON.stringify, JSON.parse, and Common Pitfalls

How to convert JavaScript objects to JSON and back — JSON.stringify, JSON.parse, the replacer and reviver hooks, and the values that don't survive the round trip.

JSON Is Text, Not an Object

JSON (JavaScript Object Notation) is a text format for exchanging data. It looks like a JavaScript object literal, but it's a string — a sequence of characters you can send over a network, save to a file, or paste into a config.

// A JavaScript object — a live value in memory.
const user = { name: "Rosa", age: 30 };

// JSON — a string of text that represents the same data.
const json = '{"name":"Rosa","age":30}';

The two are easy to mix up because they look alike. The mental model that keeps you straight: objects live in your program; JSON is what they look like on the way out the door. You convert between them with two functions: JSON.stringify (object → string) and JSON.parse (string → object).

JSON.stringify: Object to String

Turn any JavaScript value into its JSON representation:

index.js
Output
Click Run to see the output here.

The result is a single-line string with no spaces — compact, ideal for sending over the wire. The typeof check confirms it: string, not object.

For readability while debugging, pass two extra arguments. The second is a replacer (we'll get to it); passing null means "include everything." The third is indentation:

index.js
Output
Click Run to see the output here.

That's the standard pretty-print form. Use 2 or 4 spaces — matches what most tools produce.

JSON.parse: String to Object

The inverse: take a JSON string, get a JavaScript value back.

index.js
Output
Click Run to see the output here.

Once parsed, you're dealing with a regular object — dot access, bracket access, array methods, the works.

JSON.parse is picky. These all throw a SyntaxError:

JSON.parse("{name: 'Rosa'}");      // unquoted key, single quotes
JSON.parse('{"name": "Rosa",}');   // trailing comma
JSON.parse("// a comment\n{}");    // comments aren't allowed
JSON.parse("");                    // empty string

Any time the input comes from outside your program — a fetch response, a file, user input — wrap the parse in try/catch:

index.js
Output
Click Run to see the output here.

Values That Don't Survive the Round Trip

JSON supports six value types: strings, numbers, booleans, null, arrays, and plain objects. Everything else in JavaScript gets dropped, transformed, or breaks.

index.js
Output
Click Run to see the output here.

What happens:

  • Functions and undefined are silently removed from objects. Inside arrays they become null — arrays can't have gaps in JSON.
  • Date objects are serialized to an ISO string via their toJSON method. Parsing gives you back the string, not a Date.
  • BigInt throws a TypeError. JSON numbers have no equivalent.
  • Map, Set, and circular references also don't work out of the box.

The fix for Date round-tripping is the reviver function of JSON.parse:

index.js
Output
Click Run to see the output here.

The reviver runs for every key/value pair and lets you transform values on the way in.

The Replacer: Filtering What Gets Serialized

The second argument to JSON.stringify lets you control what ends up in the output. Pass an array of keys to whitelist them:

index.js
Output
Click Run to see the output here.

Or pass a function for arbitrary logic — drop fields, mask values, transform on the fly:

index.js
Output
Click Run to see the output here.

Returning undefined removes the key. Returning any other value replaces it.

Customizing with toJSON

If an object has a toJSON method, JSON.stringify calls it and serializes the return value instead. This is how Date controls its own format, and you can use the same hook:

index.js
Output
Click Run to see the output here.

Great for classes that want a consistent public shape regardless of who's serializing them.

Deep Clone (the Old Trick, and the Better One)

For years, JSON.parse(JSON.stringify(obj)) was the one-liner for deep-cloning a plain object:

index.js
Output
Click Run to see the output here.

It works — as long as the object only contains JSON-safe values. Dates, Maps, and functions all break it (see the round-trip issues above).

Modern JavaScript has structuredClone, which handles Dates, Maps, Sets, typed arrays, and circular references:

index.js
Output
Click Run to see the output here.

Reach for structuredClone when you can. Keep the JSON.parse(JSON.stringify(...)) trick in your back pocket for quick-and-dirty clones of plain data.

A Realistic Example: Fetching and Parsing

The most common place you'll touch JSON is HTTP. fetch doesn't parse JSON for you — you call .json() on the response (which is really JSON.parse on the response body):

index.js
Output
Click Run to see the output here.

Sending JSON is the reverse: JSON.stringify the body and set the Content-Type header.

await fetch("/api/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Rosa", age: 30 }),
});

These two patterns cover the vast majority of real-world JSON work.

Next: Optional Chaining

Parsed JSON often has optional fields — a user.address.city that might not exist, a response.data.items that could be missing. Accessing deeply nested properties without crashing is what optional chaining (?.) is for, and that's the next page.

Frequently Asked Questions

What's the difference between JSON and a JavaScript object?

JSON is a text format — a string that looks like a JavaScript object literal but with stricter rules. Keys must be double-quoted, strings must use double quotes, and values are limited to strings, numbers, booleans, null, arrays, and plain objects. A JavaScript object is a live value in memory that can hold functions, undefined, Date instances, and anything else.

How do I convert a JavaScript object to JSON?

Call JSON.stringify(obj). It walks the object and returns a JSON string. Pass a third argument like JSON.stringify(obj, null, 2) to pretty-print with 2-space indentation. Functions and undefined values get dropped from objects and become null inside arrays.

Why does JSON.parse throw an error?

JSON.parse is strict: trailing commas, single quotes, unquoted keys, and comments all cause a SyntaxError. Wrap the call in try/catch whenever the input comes from a network request, a file, or a user — anywhere the string might not be valid JSON.

Does JSON.stringify preserve Dates?

No. A Date becomes an ISO string like "2026-01-15T10:30:00.000Z". When you JSON.parse it back, you get that string, not a Date object. Use the reviver argument of JSON.parse to convert ISO strings back into Date instances if you need them.

Learn to code with Coddy

GET STARTED