The JSON.stringify() function is the canonical way to convert a JavaScript object to JSON. Many JavaScript frameworks use JSON.stringify() under the hood: Express' res.json() , Axios' post() , and Webpack stats all call JSON.stringify() . In this article, I'll provide a practical overview of JSON.stringify() , including error cases.

Getting Started

All modern JavaScript runtimes support JSON.stringify() . Even Internet Explorer has JSON.stringify() support since IE8. Here's an example of converting a simple object to JSON:

const obj = { answer: 42 }; const str = JSON .stringify(obj); str; typeof str;

You may see JSON.stringify() used with JSON.parse() as shown below. This pattern is one way of deep cloning a JavaScript object.

const obj = { answer: 42 }; const clone = JSON .parse( JSON .stringify(obj)); clone.answer; clone === obj;

Errors and Edge Cases

JSON.stringify() throws an error when it detects a cyclical object. In other words, if an object obj has a property whose value is obj , JSON.stringify() will throw an error.

const obj = {}; obj.prop = obj; JSON .stringify(obj);

That is the only case where JSON.stringify() throws an exception, unless you're using custom toJSON() functions or replacer functions. However, you should still wrap JSON.stringify() calls in try/catch , because circular objects do pop up in practice.

There are several edge cases where JSON.stringify() doesn't throw an error, but you might expect it does. For example, JSON.stringify() converts NaN and Infinity to null :

const obj = { nan: parseInt ( 'not a number' ), inf: Number .POSITIVE_INFINITY }; JSON .stringify(obj);

JSON.stringify() also strips out properties whose values are functions or undefined :

const obj = { fn: function ( ) {}, undef: undefined }; JSON .stringify(obj);

Pretty Printing

The first parameter to JSON.stringify() is the object to serialize to JSON. JSON.stringify() actually takes 3 parameters, and the 3rd parameter is called spaces . The spaces parameter is used for formatting JSON output in a human readable way.

You can set the spaces parameter to either be a string or a number. If spaces is not undefined, JSON.stringify() will put each key in the JSON output on its own line, and prefix each key with spaces .

const obj = { a: 1 , b: 2 , c: 3 , d: { e: 4 } }; JSON .stringify(obj); JSON .stringify(obj, null , ' ' ); JSON .stringify(obj, null , 2 );

The spaces string doesn't have to be all whitespace, although in practice it usually will be. For example:

JSON .stringify(obj, null , '__' );

Replacers

The 2nd parameter to JSON.stringify() is the replacer function. In the above examples, replacer was null . JavaScript calls the replacer function with every key/value pair in the object, and uses the value the replacer function returns. For example:

const obj = { a: 1 , b: 2 , c: 3 , d: { e: 4 } }; JSON .stringify(obj, function replacer ( key, value ) { if ( typeof value === 'number' ) { return value + 1 ; } return value; });

The replacer function is useful for omitting sensitive data. For example, suppose you wanted to omit all keys that contain the substring 'password':

const obj = { name: 'Jean-Luc Picard' , password: 'stargazer' , nested: { hashedPassword: 'c3RhcmdhemVy' } }; JSON .stringify(obj, function replacer ( key, value ) { if (key.match( /password/i )) { return undefined ; } return value; });

The toJSON() Function

The JSON.stringify() function also traverses the object looking for properties that have a toJSON() function. If it finds a toJSON() function, JSON.stringify() calls the toJSON() function and uses the return value as a replacement. For example:

const obj = { name: 'Jean-Luc Picard' , nested: { test: 'not in output' , toJSON: () => 'test' } }; JSON .stringify(obj);

The toJSON() function can return any value, including objects, primitives, or undefined . If toJSON() returns undefined , JSON.stringify() will ignore that property.

Many JavaScript modules use toJSON() to ensure sophisticated objects get serialized correctly, like Mongoose documents and Moment objects.

Moving On