UnblockDevs

How to Convert a JavaScript Object to a JSON String — JSON.stringify() Explained

Every JavaScript developer needs to convert objects to JSON strings — for API requests, localStorage, config files, logs, and test fixtures. This guide explains every way to do it: JSON.stringify() for standard cases, the space parameter for readable output, the replacer for filtering sensitive fields, and the free online tool for instant conversion without writing any code.

JSON.stringify()

The built-in JS method — no install, works in every browser and Node.js

null, 2

The magic second and third arguments for pretty-printed output

5 ways

Different methods to serialize objects — each best for different scenarios

1

The Simplest Way: JSON.stringify(object)

For the most common case — serializing a plain JavaScript object to a compact JSON string — pass the object directly to JSON.stringify() with no other arguments.

javascriptBasic object to JSON string
// Plain JavaScript object
const user = {
  id: 42,
  name: 'Alice',
  email: 'alice@example.com',
  age: 28,
  isActive: true,
  tags: ['admin', 'editor'],
};

// Convert to JSON string
const jsonString = JSON.stringify(user);

console.log(jsonString);
// '{"id":42,"name":"Alice","email":"alice@example.com","age":28,"isActive":true,"tags":["admin","editor"]}'

console.log(typeof jsonString); // 'string'

// Round-trip: parse it back to an object
const parsedBack = JSON.parse(jsonString);
console.log(parsedBack.name); // 'Alice'

Result is always a string

JSON.stringify() always returns a string (or undefined for non-JSON-representable inputs). The quotes around keys and string values, the colon separators, and the lack of trailing commas are all part of valid JSON format — required by the spec.
2

Pretty-Print: Readable Multi-Line JSON String

The default output is a compact single line — hard to read for complex objects. Pass a space value as the third argument to get indented, multi-line output.

javascriptPretty-print with 2-space indent
const config = {
  server: {
    host: 'api.example.com',
    port: 443,
    ssl: true,
  },
  database: {
    host: 'db.internal',
    port: 5432,
    name: 'production',
  },
  features: ['auth', 'analytics', 'notifications'],
};

// Compact — for sending over the network
const compact = JSON.stringify(config);
// '{"server":{"host":"api.example.com","port":443,"ssl":true},...}'

// Pretty — for config files, debugging, logs
const pretty = JSON.stringify(config, null, 2);
console.log(pretty);
// {
//   "server": {
//     "host": "api.example.com",
//     "port": 443,
//     "ssl": true
//   },
//   "database": {
//     "host": "db.internal",
//     "port": 5432,
//     "name": "production"
//   },
//   "features": [
//     "auth",
//     "analytics",
//     "notifications"
//   ]
// }

// 4-space indent — common in Python ecosystem
const wide = JSON.stringify(config, null, 4);

// Tab indent — common in some editors
const tabbed = JSON.stringify(config, null, '	');

null, 2 — the most used stringify call

JSON.stringify(obj, null, 2) is the most common form after the basic one-argument call. The null skips the replacer (no field filtering), and 2 adds 2-space indentation. It appears in config generation, test fixtures, pretty-printing API responses, and writing JSON files in Node.js.

3

Filter Fields — Only Include What You Need

When an object has sensitive data, internal fields, or too many properties for the use case, the replacer parameter filters the output.

javascriptArray replacer — whitelist specific keys
const user = {
  id: 42,
  name: 'Alice',
  email: 'alice@example.com',
  passwordHash: '$2b$10$...',
  apiKey: 'sk-live-abc123',
  sessionToken: 'tok_xyz',
  createdAt: '2024-01-15',
  updatedAt: '2024-11-10',
};

// Only serialize id, name, email — everything else is omitted
const publicUser = JSON.stringify(user, ['id', 'name', 'email'], 2);
// {
//   "id": 42,
//   "name": "Alice",
//   "email": "alice@example.com"
// }
// passwordHash, apiKey, sessionToken, createdAt, updatedAt are NOT included
javascriptFunction replacer — dynamic field exclusion
const record = {
  id: 'rec-001',
  title: 'Q4 Report',
  content: 'Full report content...',
  author: 'Alice',
  internalNotes: 'Draft — do not share',
  _metadata: { version: 3, checksum: 'abc123' },
  publishedAt: new Date('2024-11-01'),
};

// Function: called for every key-value pair at every depth
const cleanReplacer = (key, value) => {
  if (key === '') return value;            // always return root object
  if (key.startsWith('_')) return undefined; // omit private _fields
  if (key === 'internalNotes') return undefined;
  return value;
};

JSON.stringify(record, cleanReplacer, 2);
// {
//   "id": "rec-001",
//   "title": "Q4 Report",
//   "content": "Full report content...",
//   "author": "Alice",
//   "publishedAt": "2024-11-01T00:00:00.000Z"
// }
4

Convert Nested Objects and Arrays

JSON.stringify() handles nested objects and arrays recursively. The depth is unlimited — it serializes the entire object graph in one call.

javascriptDeeply nested objects and arrays
const order = {
  id: 'ORD-9001',
  customer: {
    id: 'CUST-42',
    name: 'Alice Smith',
    address: {
      street: '123 Main St',
      city: 'London',
      country: 'UK',
      postcode: 'EC1A 1BB',
    },
  },
  items: [
    { sku: 'PROD-1', name: 'Widget A', qty: 2, price: 9.99 },
    { sku: 'PROD-2', name: 'Widget B', qty: 1, price: 19.99 },
  ],
  total: 39.97,
  status: 'pending',
  createdAt: new Date().toISOString(),
};

const json = JSON.stringify(order, null, 2);
// Produces a fully nested, 30+ line JSON string
// Every array item gets its own indented block
// Date is already an ISO string
5

Converting Objects in Common Scenarios

javascriptScenario 1: Send object to a REST API (fetch)
const newProduct = {
  name: 'Wireless Mouse',
  price: 29.99,
  category: 'electronics',
  inStock: true,
  tags: ['wireless', 'peripheral', 'office'],
};

const response = await fetch('https://api.example.com/products', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer TOKEN',
  },
  body: JSON.stringify(newProduct),  // MUST be a string — not an object
});

const created = await response.json();
console.log('Created product ID:', created.id);
javascriptScenario 2: Save object to localStorage
// localStorage can only store strings
const userPreferences = {
  theme: 'dark',
  language: 'en',
  notifications: { email: true, push: false, sms: false },
  dashboardWidgets: ['revenue', 'users', 'conversion'],
};

// Save
localStorage.setItem('prefs', JSON.stringify(userPreferences));

// Load
const prefs = JSON.parse(localStorage.getItem('prefs') ?? '{}');
console.log(prefs.theme); // 'dark'
console.log(prefs.notifications.email); // true
javascriptScenario 3: Write a JSON file in Node.js
import fs from 'fs';

const data = {
  version: '2.1.0',
  generatedAt: new Date().toISOString(),
  users: [
    { id: 1, name: 'Alice', role: 'admin' },
    { id: 2, name: 'Bob', role: 'viewer' },
  ],
};

// Write with 2-space indent for human-readable JSON files
fs.writeFileSync('./output/users.json', JSON.stringify(data, null, 2), 'utf8');

// For compact files (smaller, machine-readable)
fs.writeFileSync('./cache/users.min.json', JSON.stringify(data), 'utf8');
javascriptScenario 4: Log objects in structured logging
// Many log transports expect string values or JSON serializable structures
// JSON.stringify prevents [object Object] in string concatenation

const requestContext = {
  requestId: 'req-abc123',
  userId: 42,
  path: '/api/orders',
  method: 'POST',
  durationMs: 143,
};

// Simple string concat — broken
console.log('Request finished: ' + requestContext);
// 'Request finished: [object Object]'  ← not useful

// Correct
console.log('Request finished:', JSON.stringify(requestContext));
// 'Request finished: {"requestId":"req-abc123","userId":42,...}'
6

What JSON.stringify() Cannot Convert

Not all JavaScript values can be represented in JSON. Knowing which values get silently dropped vs. which throw errors saves hours of debugging.

undefined → omitted or null

In object properties: silently omitted. In arrays: becomes null (to preserve index). As the top-level value: returns the JS value undefined (not a string). Use null to represent intentionally absent values.

Functions → omitted

Object properties with function values are silently omitted. Functions in arrays become null. JSON cannot represent executable code — this is intentional for security. Classes serialize as empty objects {} unless they have toJSON().

Symbol → omitted

Symbol-keyed properties are always omitted. Symbol values in objects are omitted; in arrays they become null. Symbols are JavaScript-internal identifiers with no JSON equivalent.

Circular references → throws

If an object references itself (directly or indirectly), JSON.stringify() throws TypeError: "Converting circular structure to JSON". Use the flatted package or a custom replacer that tracks seen objects to handle circular structures.

BigInt → throws

JSON.stringify() throws TypeError: "Do not know how to serialize a BigInt". Convert BigInt to string or number first: JSON.stringify({ id: bigIntValue.toString() }). JSON numbers have precision limits that BigInt was designed to exceed.

Date → ISO string (via toJSON)

Date objects have a built-in toJSON() method that produces an ISO 8601 string. So JSON.stringify(new Date()) produces the current time as a quoted string — not a Date object. Parsing it back gives a string, not a Date; re-construct with new Date(str).

Forgetting that functions in objects are silently dropped

Functions silently vanish — no warning, no error

❌ Bad
const service = {
  name: 'UserService',
  baseUrl: 'https://api.example.com',
  fetch: async (id) => { /* ... */ },  // a method
  validate: (data) => data.id > 0,    // another method
};

JSON.stringify(service);
// '{"name":"UserService","baseUrl":"https://api.example.com"}'
// fetch and validate silently disappeared!
// Logging this gives a false picture of the object

Explicitly define what to serialize via toJSON() or plain data object

✅ Good
// Option 1: build a plain serializable object for logging/transfer
const serializable = {
  name: service.name,
  baseUrl: service.baseUrl,
  // methods listed by name only for documentation
  methods: ['fetch', 'validate'],
};
JSON.stringify(serializable, null, 2);

// Option 2: use .toJSON() to control serialization
class UserService {
  constructor() { this.name = 'UserService'; this.baseUrl = '...'; }
  toJSON() { return { name: this.name, baseUrl: this.baseUrl }; }
  async fetch(id) { /* ... */ }
}
7

Use the JSON.stringify() Online Tool

For converting complex objects without opening a browser console or Node.js REPL, the online tool handles it instantly.

1

Paste your JavaScript object

The tool accepts JavaScript object literals with unquoted keys, single-quoted strings, trailing commas, and comments — not just strict JSON. It normalizes the input automatically.

2

Choose compact or pretty output

Select your indent level — compact (0), 2-space, 4-space, or tab. The byte count updates instantly so you can see the size difference.

3

Review the JSON string

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

4

Copy or download the result

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

Convert any JS object to JSON string instantly

Paste any JavaScript object at unblockdevs.com/json-stringify-online — get compact or pretty-printed JSON in one click. All processing happens in your browser — your data never leaves your machine.

Frequently Asked Questions