Back to Blog
    JSONJavaScriptJSON StringifyAdvancedTutorial

    Advanced JSON Stringify Techniques: Replacer, Space, and Custom Serialization

    J
    Jsonkithub Team
    December 15, 2025
    11 min read

    Most developers use JSON Stringify for simple conversions, but it offers far more control and flexibility through optional parameters and custom serialization logic. These advanced techniques let you transform data, filter sensitive fields, format output, handle edge cases, and even define how custom objects serialize themselves.

    In this guide, we'll explore the replacer function, the space parameter, custom toJSON methods, and best practices for advanced JSON serialization in JavaScript.

    Overview of JSON Stringify Advanced Features

    The full signature of JSON Stringify reveals its power:

    JSON.stringify(value, replacer, space)

    While most developers use only the first argument, the second and third parameters unlock powerful transformations:

    • replacer: A function or array that controls which properties are included and how they're transformed.
    • space: A number or string that adds indentation for pretty-printing.

    You can also define custom toJSON methods on your objects to control exactly how they serialize.

    Must Read: What Is JSON Stringify? Complete Guide with Examples

    Using the Replacer Function for Filtering and Transformation

    The replacer parameter can be a function that gets called for every key–value pair during serialization.

    Function signature:

    function replacer(key, value) { // return modified value or undefined to exclude }

    Filtering sensitive fields

    const user = { name: "Alex", email: "alex@example.com", password: "secret123", apiKey: "sk_live_abc123" }; const safeJson = JSON.stringify(user, (key, value) => { if (key === "password" || key === "apiKey") return undefined; return value; }); console.log(safeJson); // → {"name":"Alex","email":"alex@example.com"}

    Sensitive data like passwords, API keys, or tokens can be excluded before logging or sending to external systems.

    Transforming values during serialization

    const product = { name: "Laptop", price: 1200.5, inStock: true }; const transformed = JSON.stringify(product, (key, value) => { if (key === "price") return `$${value.toFixed(2)}`; return value; }); console.log(transformed); // → {"name":"Laptop","price":"$1200.50","inStock":true}

    You can format numbers, modify strings, or convert values on the fly.

    Using an array as a replacer

    When replacer is an array, it defines a whitelist of properties to include:

    const data = { id: 101, name: "Product A", price: 50, internal: "confidential" }; const publicData = JSON.stringify(data, ["id", "name", "price"]); console.log(publicData); // → {"id":101,"name":"Product A","price":50}

    This is cleaner than a function when you only want to select specific fields.

    Using the Space Parameter for Pretty-Printing

    The space parameter controls indentation, making JSON output human-readable.

    Syntax:

    JSON.stringify(value, null, space)
    • space can be a number (0–10) or a string (up to 10 characters).
    • A number adds that many spaces per indentation level.
    • A string uses that text for indentation.

    Example: Adding spaces

    const obj = { name: "Alex", age: 28, active: true }; console.log(JSON.stringify(obj, null, 2));

    Output:

    { "name": "Alex", "age": 28, "active": true }

    Example: Using a custom indentation string

    console.log(JSON.stringify(obj, null, "→ "));

    Output:

    { "name": "Alex", "age": 28, "active": true }

    Pretty-printing is essential for debugging, logging, or generating readable JSON files.

    Custom Serialization with toJSON Methods

    Objects can define a toJSON method that controls how they serialize. JSON Stringify automatically calls this method if it exists.

    Basic example

    const user = { username: "alex", password: "secret123", toJSON() { return { username: this.username }; } }; console.log(JSON.stringify(user)); // → {"username":"alex"}

    The toJSON method excluded the password automatically.

    Working with Date objects

    JavaScript Date objects already include a toJSON method that returns an ISO 8601 string:

    const event = { name: "Launch", date: new Date("2025-12-31T23:59:59Z") }; console.log(JSON.stringify(event)); // → {"name":"Launch","date":"2025-12-31T23:59:59.000Z"}

    You can override toJSON on custom date wrappers to control the format.

    Custom class serialization

    class Product { constructor(id, name, price) { this.id = id; this.name = name; this.price = price; this.createdAt = new Date(); } toJSON() { return { id: this.id, name: this.name, price: `$${this.price.toFixed(2)}` }; } } const item = new Product(1, "Widget", 19.99); console.log(JSON.stringify(item)); // → {"id":1,"name":"Widget","price":"$19.99"}

    This pattern keeps serialization logic encapsulated within the class.

    Handling Special Cases and Edge Cases

    Dealing with undefined, functions, and symbols

    const obj = { name: "Alex", temp: undefined, log: () => {}, [Symbol("id")]: 123 }; console.log(JSON.stringify(obj)); // → {"name":"Alex"}

    All three types are omitted from the output because JSON only supports data, not behavior or meta-values.

    Handling circular references

    const obj = { name: "Alex" }; obj.self = obj; try { JSON.stringify(obj); } catch (err) { console.log(err.message); // → Converting circular structure to JSON }

    You must remove or replace circular references manually, or use a library like flatted.

    Serializing Map and Set objects

    Maps and Sets do not serialize to meaningful JSON by default:

    const map = new Map([["key", "value"]]); console.log(JSON.stringify(map)); // → {}

    You must convert them to arrays first:

    const serialized = JSON.stringify(Array.from(map.entries())); console.log(serialized); // → [["key","value"]]

    Handling BigInt

    BigInt values are not supported by JSON Stringify:

    const big = { id: 123n }; JSON.stringify(big); // TypeError: Do not know how to serialize a BigInt

    Convert BigInt to a string manually before stringifying.

    Combining Replacer, Space, and toJSON

    You can combine all three techniques for maximum control:

    class User { constructor(name, password, createdAt) { this.name = name; this.password = password; this.createdAt = createdAt; } toJSON() { return { name: this.name, createdAt: this.createdAt.toISOString() }; } } const user = new User("Alex", "secret", new Date()); const output = JSON.stringify( user, (key, value) => (key === "createdAt" ? value.slice(0, 10) : value), 2 ); console.log(output);

    Output:

    { "name": "Alex", "createdAt": "2025-12-15" }

    This example combines:

    • toJSON for initial control
    • replacer for further transformation
    • space for readable formatting

    Real-World Use Cases for Advanced JSON Stringify

    API payloads with field filtering

    const sendUserData = (user) => { const payload = JSON.stringify(user, ["id", "name", "email"]); fetch("/api/users", { method: "POST", headers: { "Content-Type": "application/json" }, body: payload }); };

    Logging with pretty-print

    console.log("State:", JSON.stringify(state, null, 2));

    Exporting configuration files

    const config = { theme: "dark", lang: "en", debug: false }; fs.writeFileSync("config.json", JSON.stringify(config, null, 2));

    Sanitizing data before transmission

    const clean = JSON.stringify(data, (k, v) => typeof v === "string" ? v.trim() : v );

    Best Practices for Advanced JSON Stringify

    • Use replacer functions to exclude sensitive data or transform values.
    • Use space for debugging and file exports, but omit it for production APIs to save bytes.
    • Define toJSON methods on classes for clean, reusable serialization logic.
    • Always handle circular references, undefined, and BigInt before stringifying.
    • Validate serialized output before sending to external systems.
    • Combine techniques (replacer + space + toJSON) for complex use cases.

    Conclusion: Unlock the Full Power of JSON Stringify

    JSON Stringify is far more than a simple object-to-string converter. With replacer functions, the space parameter, and custom toJSON methods, you can filter, transform, format, and control every aspect of JSON serialization in JavaScript.

    By mastering these advanced techniques, you'll write safer APIs, cleaner logs, and more maintainable code.

    Tools on JSON Kithub help:

    FAQs On Advanced JSON Stringify Techniques

    Q1. What is the replacer parameter in JSON Stringify?

    The replacer can be a function or array that controls which properties are included in the output and how values are transformed during serialization.

    Q2. How do I pretty-print JSON with JSON Stringify?

    Use the third space parameter, such as JSON.stringify(obj, null, 2), to add indentation and make the JSON output more readable.

    Q3. What is a toJSON method?

    A toJSON method is a custom function you define on an object that controls how that object serializes when passed to JSON Stringify.

    Q4. Can I filter out sensitive fields with JSON Stringify?

    Yes. Use a replacer function to return undefined for any key you want to exclude, such as password or apiKey.

    Q5. How do I handle circular references in JSON Stringify?

    You must manually remove or replace circular references before calling JSON Stringify, or use a library like flatted that supports circular structures.

    Ready to Try Our JSON Tools?

    Format, validate, and transform your JSON data with our free online tools.