JSON.stringify() Complete Guide — Options, Replacer, Space & Real-World Examples

JSON.stringify() converts JavaScript objects to JSON strings — but most developers only ever use its simplest form. The function takes three parameters, handles a dozen special value types differently, and has a replacer function that can filter and transform your data on the fly. This guide covers everything: the full signature, all three parameters, output formatting, real-world patterns, and the most common mistakes.

3 params

value, replacer, space — most devs only ever use the first

undefined

Silently stripped from objects — the #1 cause of data loss bugs

1 tool

Simulate JSON.stringify() instantly — no Node.js or browser console needed

1

JSON.stringify() Signature — All Three Parameters

Most code uses only the first parameter. Understanding all three unlocks formatting control, field filtering, and data transformation that would otherwise require manual loops.

javascriptFull JSON.stringify() signature
JSON.stringify(value, replacer, space)

// value    — required: the value to serialize
//             objects, arrays, strings, numbers, booleans, null
// replacer — optional: controls which fields are included
//             Array<string> → whitelist of keys to keep
//             Function(key, value) → return value to keep, undefined to omit
// space    — optional: indentation
//             0 or omit → compact, single-line output
//             2 → 2-space indent (most common for readability)
//             4 → 4-space indent
//             '\t' → tab indent

// Returns: a JSON string, or undefined for top-level undefined/Function/Symbol
// Throws:  TypeError for circular references or BigInt values

value (required)

Any JavaScript value. Objects and arrays are recursively serialized. Primitives become their JSON representation. undefined, Symbol, and Function values are stripped from object properties or become null in arrays.

replacer (optional)

An array of strings to whitelist specific keys, or a function called for every key-value pair that returns the value to serialize — or undefined to omit it. Pass null to skip replacer while still using the space parameter.

space (optional)

A number (1–10) of spaces, or a string (up to 10 chars) used as the indent. Omit for compact output. Use 2 for standard pretty-print. Numbers above 10 and strings longer than 10 chars are capped automatically.

Return value

A valid JSON string, or the JavaScript value undefined (not a string) if the top-level input is undefined, a Function, or a Symbol. Throws TypeError for circular references and BigInt values.

2

Compact vs. Pretty-Print — the space Parameter

The space parameter controls output format. Compact is smaller — ideal for API payloads, localStorage, and cookies. Pretty is human-readable — ideal for debugging, config files, and log entries.

javascriptspace parameter examples — all formats
const user = {
  id: 42,
  name: 'Alice',
  roles: ['admin', 'editor'],
  address: { city: 'London', country: 'UK' },
};

// Compact — no space argument
JSON.stringify(user);
// '{"id":42,"name":"Alice","roles":["admin","editor"],"address":{"city":"London","country":"UK"}}'

// 2-space indent — most common for readability
JSON.stringify(user, null, 2);
// {
//   "id": 42,
//   "name": "Alice",
//   "roles": [
//     "admin",
//     "editor"
//   ],
//   "address": {
//     "city": "London",
//     "country": "UK"
//   }
// }

// Tab indent — preferred for some config file formats
JSON.stringify(user, null, '	');

// space: 0 — explicit compact (same as omitting space)
JSON.stringify(user, null, 0);

See the output instantly — no code required

Paste any JavaScript object into the JSON.stringify() online tool and switch between compact, 2-space, 4-space, and tab output. Also shows byte count so you can see exactly how much space pretty-printing adds.
3

The replacer Parameter — Filter and Transform Fields

Pass an array to whitelist keys. Pass a function to apply custom transformation or omission logic to every value, recursively.

javascriptreplacer array — key whitelist
const user = {
  id: 42,
  name: 'Alice',
  email: 'alice@example.com',
  passwordHash: '$2b$10$...',
  apiKey: 'sk-live-xyz789',
  roles: ['admin', 'editor'],
};

// Only include id, name, roles — silently omit everything else
JSON.stringify(user, ['id', 'name', 'roles'], 2);
// {
//   "id": 42,
//   "name": "Alice",
//   "roles": ["admin", "editor"]
// }
javascriptreplacer function — dynamic transform
const data = {
  userId: 42,
  name: 'Alice',
  password: 'hunter2',
  apiKey: 'sk-live-xyz789',
  lastLogin: new Date('2024-11-15T10:30:00Z'),
  balance: 9.876543,
};

const safeReplacer = (key, value) => {
  // Root call always has key === '' — pass through unchanged
  if (key === '') return value;

  // Omit secrets
  if (key === 'password' || key === 'apiKey') return undefined;

  // Dates are already serialized to ISO string by Date.toJSON() before
  // replacer runs — value will be a string like '2024-11-15T10:30:00.000Z'

  // Round floating-point numbers to 2 decimal places
  if (typeof value === 'number' && !Number.isInteger(value)) {
    return parseFloat(value.toFixed(2));
  }

  return value;
};

JSON.stringify(data, safeReplacer, 2);
// {
//   "userId": 42,
//   "name": "Alice",
//   "lastLogin": "2024-11-15T10:30:00.000Z",
//   "balance": 9.88
// }

Replacer receives all keys recursively

The replacer function is called for every key-value pair at every depth level. For the root object, key is an empty string (key === ''). Always return value for the root call — returning undefined at the root produces the JavaScript value undefined, not a JSON string.

4

toJSON() — Custom Serialization per Class

Objects with a toJSON() method control their own serialization. JSON.stringify() calls toJSON() and stringifies the return value. This is how Date objects produce ISO strings automatically.

javascripttoJSON() examples
// Date.prototype.toJSON() exists — produces ISO 8601 strings
const event = { name: 'Launch', at: new Date('2024-11-15T10:00:00Z') };
JSON.stringify(event);
// '{"name":"Launch","at":"2024-11-15T10:00:00.000Z"}'

// Custom toJSON() on your own class
class Price {
  constructor(cents, currency) {
    this.cents = cents;
    this.currency = currency;
  }

  toJSON() {
    // Serialize as a compact single value instead of {cents, currency}
    return (this.cents / 100).toFixed(2) + ' ' + this.currency;
  }
}

const order = { id: 'ORD-1', subtotal: new Price(4999, 'USD') };
JSON.stringify(order);
// '{"id":"ORD-1","subtotal":"49.99 USD"}'
5

Practical Patterns — Real-World JSON.stringify() Usage

javascriptAPI requests — always stringify the body
// fetch() requires a string body — JSON.stringify converts the payload
const response = await fetch('https://api.example.com/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' }),
});

// Axios does this automatically (pass an object, Axios calls JSON.stringify)
const { data } = await axios.post('/users', { name: 'Alice', email: 'alice@example.com' });
javascriptlocalStorage — objects must be stringified
// localStorage only stores strings
const cart = {
  items: [{ id: 'SKU-1', qty: 2 }, { id: 'SKU-3', qty: 1 }],
  coupon: 'SAVE10',
};

// Save (compact — no need for pretty-print in storage)
localStorage.setItem('cart', JSON.stringify(cart));

// Retrieve and restore
const savedCart = JSON.parse(localStorage.getItem('cart') ?? '{}');
console.log(savedCart.items.length); // 2
javascriptQuick deep clone (with caveats)
// Fast deep clone — works for plain objects with JSON-compatible values
const original = { name: 'Alice', scores: [10, 20, 30], meta: { active: true } };
const clone = JSON.parse(JSON.stringify(original));

clone.scores.push(40);
console.log(original.scores); // [10, 20, 30] — unchanged
console.log(clone.scores);    // [10, 20, 30, 40]

// Caveats: undefined removed, Date becomes string, no Map/Set/Function
// For production cloning: use structuredClone() (Node 17+, all modern browsers)
const betterClone = structuredClone(original); // preserves all types
javascriptReadable object logging
// Avoid [object Object] in string concatenation and some loggers
const user = { id: 42, name: 'Alice', role: 'admin' };

console.log('User: ' + user);                          // 'User: [object Object]'
console.log('User:', JSON.stringify(user));             // 'User: {"id":42,...}'
console.log('User:', JSON.stringify(user, null, 2));   // multi-line, pretty

// Compact for one-liners in structured logs
logger.info({ event: 'login', user: JSON.stringify(user) });
6

Common JSON.stringify() Mistakes

Expecting undefined values to be preserved in objects

undefined silently dropped — server never sees the field

❌ Bad
const form = {
  name: 'Alice',
  middleName: undefined, // user left it blank
  age: 30,
};

const body = JSON.stringify(form);
// '{"name":"Alice","age":30}'
// middleName is GONE — the PATCH request won't clear it on the server

null preserved — server knows the field was intentionally cleared

✅ Good
// Use null to explicitly represent "no value"
const form = { name: 'Alice', middleName: null, age: 30 };
JSON.stringify(form);
// '{"name":"Alice","middleName":null,"age":30}'

// Or convert undefined to null with a replacer:
JSON.stringify(form, (k, v) => (v === undefined ? null : v));
// '{"name":"Alice","middleName":null,"age":30}'

Using JSON.stringify() to compare objects with different key insertion order

Key order dependent — breaks silently on different data sources

❌ Bad
const a = { x: 1, y: 2 };
const b = { y: 2, x: 1 };  // same data, different key order

JSON.stringify(a) === JSON.stringify(b);
// false — key order differs, even though values are identical

Sort keys first for reliable structural comparison

✅ Good
// Sort keys first for stable, order-independent comparison
const sortedStringify = (obj) =>
  JSON.stringify(obj, Object.keys(obj).sort());

sortedStringify(a) === sortedStringify(b); // true

// For production: use a deep equality library
// import { isEqual } from 'lodash';  → isEqual(a, b) === true
7

Try JSON.stringify() Online

For quick experiments, debugging, or checking how a specific value serializes — the online tool is faster than opening a browser console.

1

Paste any JavaScript object or JSON

The tool accepts JavaScript object literals (unquoted keys, trailing commas) and strict JSON. It normalizes the input before running stringify.

2

Choose indent level

Switch between compact (0), 2-space, 4-space, and tab. The byte count updates instantly so you can see the cost of pretty-printing.

3

View the exact output

The result is the exact string JSON.stringify() produces — all keys quoted, special characters escaped, undefined removed, null and boolean values serialized correctly.

4

Copy or download

Copy the string to clipboard for use in code, or download as a .json file for use in fixtures, config files, or API mock data.

Frequently Asked Questions