SKU // 120

JSON Stringify

JSON.stringify turns a JavaScript value into JSON text, ready to save, send, or print. It is the opposite of JSON.parse. Most values convert exactly as you would expect, but some have no JSON form and are quietly dropped, changed, or rejected, so it pays to know the rules.

// JSON.stringify(value)

const user = { name: "Ava", age: 16, tags: ["js", "css"], active: true };
const text = JSON.stringify(user);
console.log(text);
console.log(typeof text);
{"name":"Ava","age":16,"tags":["js","css"],"active":true} string

The text is compact: no extra spaces or line breaks, with every key in double quotes. Anything you can stringify, you can later JSON.parse back into an equal value.

console.log(JSON.stringify("hello"));
console.log(JSON.stringify(42));
console.log(JSON.stringify(true));
console.log(JSON.stringify(null));
console.log(JSON.stringify([1, "two", false]));
"hello" 42 true null [1,"two",false]

// Pretty Printing: the Third Argument

The full call is JSON.stringify(value, replacer, space). For now pass null as the replacer and a number as space: that many spaces of indentation are added, and every item goes on its own line.

const user = { name: "Ava", tags: ["js", "css"] };
console.log(JSON.stringify(user, null, 2));
console.log(JSON.stringify(user, null, "--"));
{ "name": "Ava", "tags": [ "js", "css" ] } { --"name": "Ava", --"tags": [ ----"js", ----"css" --] }

Use the indented form when a person will read it, such as a log or a file you want to open and edit. Use the compact form when size matters, such as data sent over the network. The indentation number is capped at 10.

// Values That Are Dropped or Changed

JSON cannot hold everything JavaScript can. What stringify does about it depends on where the value sits:

Value In an object In an array
undefined, a function, a Symbolinside an object: the key is left outinside an array: becomes null
NaN, Infinitybecomes nullbecomes null
Datebecomes an ISO text stringbecomes an ISO text string
Map, Setbecomes {}becomes {}
const thing = { a: 1, b: undefined, c: function () {}, d: Symbol("x"), e: null, f: NaN };
console.log(JSON.stringify(thing));
console.log(JSON.stringify([undefined, function () {}, NaN]));
console.log(JSON.stringify(undefined));
{"a":1,"e":null,"f":null} [null,null,null] undefined
Silent data loss
Nothing warns you when a key disappears. A user object holding a function, an undefined field, or a Map will stringify without complaint and come back from JSON.parse missing pieces.
const scores = new Map([["ava", 92], ["ben", 85]]);
console.log(JSON.stringify(scores));
console.log(JSON.stringify([...scores]));
console.log(JSON.stringify(Object.fromEntries(scores)));
{} [["ava",92],["ben",85]] {"ava":92,"ben":85}

// Dates and toJSON

A Date has a toJSON method, and stringify calls it. Any object can define its own toJSON to control how it is written:

console.log(JSON.stringify({ when: new Date(Date.UTC(2026, 9, 2)) }));

const temp = {
  celsius: 21,
  toJSON() {
    return { c: this.celsius, f: this.celsius * 9 / 5 + 32 };
  }
};
console.log(JSON.stringify(temp));
{"when":"2026-10-02T00:00:00.000Z"} {"c":21,"f":69.8}

// The Replacer: Choosing What Is Included

The second argument filters or changes the output. Give it an array of key names to keep only those keys:

const user = { name: "Ava", password: "secret", grade: 10, id: 7 };
console.log(JSON.stringify(user, ["name", "grade"]));
{"name":"Ava","grade":10}

Or give it a function, called with each key and value (the same shape as the reviver for parse). Return the value to keep it, a changed value to alter it, or undefined to leave the key out:

const order = { item: "Pen", price: 2.5, secretCode: "x9" };
const text = JSON.stringify(order, (key, value) => {
  if (key === "secretCode") return undefined;
  if (typeof value === "number") return value * 100;
  return value;
});
console.log(text);
{"item":"Pen","price":250}

// Errors: BigInt and Circular References

Two things make stringify throw instead of dropping a value. A BigInt has no JSON form at all, and an object that contains itself (a circular reference) would need infinite text:

try {
  JSON.stringify({ n: 10n });
} catch (error) {
  console.log(error.name);
}

const a = { name: "loop" };
a.self = a;
try {
  JSON.stringify(a);
} catch (error) {
  console.log(error.name);
}
TypeError TypeError
A quick-and-dirty copy
JSON.parse(JSON.stringify(obj)) makes a deep copy of simple data, and you will see it everywhere. It loses dates (they become strings), functions, undefined, and Map/Set, so structuredClone is the better tool when it is available.

// Quick Check

What does this log?

console.log(JSON.stringify({ a: 1, b: undefined }));
Show answer
{"a":1}. A key whose value is undefined is left out of the JSON.

What does JSON.stringify([undefined]) give?

  1. "[]"
  2. "[null]"
  3. "[undefined]"
  4. It throws an error
Show answer
B. Inside an array, undefined becomes null so the positions stay in place.

How do you make JSON.stringify write each item on its own line, indented by two spaces?

Show answer
Pass 2 as the third argument: JSON.stringify(value, null, 2).

// Try It

  1. Click Open Playground and run it. Predict the output before you read it
  2. Stringify an object that has a Date in it, then parse it back. What is the date now?
  3. Use a replacer array to print only two keys of an object that has five
  4. Make an object with a circular reference and catch the error
// Video Walkthroughs
Last updated: Oct 11, 2026, 5:50 PM ET