JSON Formatter JavaScript — JSON.stringify()

·Front-end & Node.js Developer·Geprüft vonMarcus Webb·Veröffentlicht

Nutze das kostenlose JSON Formatter & Beautifier direkt im Browser – keine Installation erforderlich.

JSON Formatter & Beautifier online testen →

Wenn ich API-Antworten in Node.js debugge, ist ein Haufen minimiertes JSON das Erste, was mich aufhält — ein einziger Aufruf von JSON.stringify(data, null, 2) und die Struktur wird sofort lesbar. Um JSON in JavaScript zu formatieren, brauchst du nichts außer der Laufzeitumgebung: JSON.stringify ist in jeden Browser und jede Node.js-Umgebung eingebaut, keine Installation nötig. Wenn du nur ein schnelles Ergebnis ohne Code brauchst, erledigt der JSON Formatter von ToolDeck das sofort. Dieser Leitfaden deckt alles Praktische ab: den space-Parameter, Replacer-Arrays und -Funktionen, den Umgang mit Date, BigInt und zirkulären Referenzen, das Lesen und Schreiben von JSON-Dateien in Node.js (18+), CLI-Pretty-Printing und die fast-json-stringify-Bibliothek für die Serialisierung im Produktionsbetrieb.

  • JSON.stringify(data, null, 2) ist in jeden Browser und Node.js eingebaut — keine Installation erforderlich.
  • Der replacer-Parameter akzeptiert ein Array (Schlüssel-Whitelist) oder eine Funktion (Werte transformieren) — nutze ihn zum Maskieren sensibler Felder.
  • Date-Objekte werden automatisch über toJSON() → ISO 8601-String serialisiert; BigInt wirft einen TypeError und erfordert einen benutzerdefinierten Replacer.
  • Zirkuläre Referenzen werfen TypeError — behebe das mit einem WeakSet in einer Replacer-Funktion oder der flatted-Bibliothek.
  • Für CLI-Pretty-Printing nutze node -p "JSON.stringify(require('./file.json'),null,2)" — keine zusätzlichen Tools nötig.

Was ist JSON-Formatierung?

JSON-Formatierung (auch Pretty-Printing genannt) verwandelt einen kompakten, minimierten JSON-String in ein für Menschen lesbares Layout mit einheitlicher Einrückung und Zeilenumbrüchen. Die zugrundeliegenden Daten sind identisch — nur der Whitespace ändert sich. Kompaktes JSON ist optimal für die Netzwerkübertragung, wo jedes Byte zählt; formatiertes JSON ist optimal für Debugging, Code-Reviews und Log-Inspektion. JavaScripts JSON.stringify() erledigt beides in einem einzigen Aufruf, indem man den space-Parameter umschaltet.

Before · json
After · json
{"orderId":"ord_8f2a91bc","status":"shipped","items":[{"sku":"HDMI-4K-2M","qty":2,"unitPrice":12.99}],"total":25.98}
{
  "orderId": "ord_8f2a91bc",
  "status": "shipped",
  "items": [
    {
      "sku": "HDMI-4K-2M",
      "qty": 2,
      "unitPrice": 12.99
    }
  ],
  "total": 25.98
}

JSON.stringify() — Der eingebaute Formatter

JSON.stringify() ist eine globale Funktion in jeder JavaScript-Umgebung — Browser, Node.js, Deno, Bun — ohne Import. Das dritte Argument, space, steuert die Einrückung: Übergib eine Zahl für diese Anzahl Leerzeichen pro Ebene oder den String '\t' für Tabs. Lässt du ihn weg (oder übergibst null), erhältst du kompakte einzeilige Ausgabe.

JavaScript — minimal working example
const serverConfig = {
  host: "api.payments.internal",
  port: 8443,
  workers: 4,
  tls: { enabled: true, cert: "/etc/ssl/certs/api.pem" },
  rateLimit: { requestsPerMinute: 1000, burst: 50 }
}

console.log(JSON.stringify(serverConfig, null, 2))
// {
//   "host": "api.payments.internal",
//   "port": 8443,
//   "workers": 4,
//   "tls": {
//     "enabled": true,
//     "cert": "/etc/ssl/certs/api.pem"
//   },
//   "rateLimit": {
//     "requestsPerMinute": 1000,
//     "burst": 50
//   }
// }

Der space-Parameter akzeptiert entweder eine Zahl (1–10 Leerzeichen) oder einen String. Ein Tab-Zeichen erzeugt Ausgaben, die viele Editoren und Diff-Tools bevorzugen. Du kannst auch alle drei Parameter kombinieren — hier ist ein Muster, das ich beim Schreiben von formatiertem JSON in Konfigurationsdateien verwende:

JavaScript — space variations
const telemetryEvent = {
  eventId: "evt_3c7f9a2b",
  service: "checkout-api",
  severity: "warn",
  latencyMs: 342,
  region: "eu-west-1",
  tags: ["payment", "timeout", "retry"]
}

// 2-Leerzeichen-Einrückung (am häufigsten in JS-Projekten)
JSON.stringify(telemetryEvent, null, 2)

// Tab-Einrückung (von manchen Lintern und Config-Tools bevorzugt)
JSON.stringify(telemetryEvent, null, '\t')

// Kompakt — kein Whitespace (für Netzwerkübertragung)
JSON.stringify(telemetryEvent)
// {"eventId":"evt_3c7f9a2b","service":"checkout-api",...}
Hinweis:undefined-, Funktions- und Symbol-Werte werden stillschweigend aus der Ausgabe ausgelassen. Ist ein Property-Wert undefined, erscheint dieser Schlüssel überhaupt nicht im serialisierten String — das ist eine häufige Fehlerquelle beim Loggen von Objekten mit optionalen Feldern.

Replacer-Funktionen — Ausgabe filtern und transformieren

Das zweite Argument für JSON.stringify() ist der Replacer. Er kommt in zwei Formen: ein Array, das bestimmte Schlüssel auf die Whitelist setzt, oder eine Funktion, die für jedes Schlüssel/Wert-Paar aufgerufen wird und Werte filtern, transformieren oder redigieren kann. Die Array-Form nutze ich, wenn ich schnell eine Teilmenge brauche, die Funktionsform, wenn ich sensible Daten vor dem Loggen maskieren muss.

Array-Replacer — Bestimmte Schlüssel auf die Whitelist setzen

JavaScript — array replacer
const order = {
  orderId: "ord_8f2a91bc",
  customer: {
    id: "usr_4421",
    email: "l.bauer@beispiel.de",
    passwordHash: "bcrypt:$2b$12$XKzV..."
  },
  items: [{ sku: "HDMI-4K-2M", qty: 2, unitPrice: 12.99 }],
  createdAt: "2026-03-10T14:22:00Z"
}

// Nur sichere Felder in die Log-Ausgabe aufnehmen
const safeLog = JSON.stringify(order, ["orderId", "items", "createdAt"], 2)
// {
//   "orderId": "ord_8f2a91bc",
//   "items": [{ "sku": "HDMI-4K-2M", "qty": 2, "unitPrice": 12.99 }],
//   "createdAt": "2026-03-10T14:22:00Z"
// }
// passwordHash und customer.email werden ausgeschlossen

Funktions-Replacer — Werte transformieren

JavaScript — function replacer
const auditRecord = {
  requestId: "req_7d2e91",
  user: { id: "usr_4421", email: "l.bauer@beispiel.de", apiKey: "sk-live-eKx9..." },
  action: "update_billing",
  timestamp: new Date("2026-03-10T14:22:00Z"),
  durationMs: 87
}

function safeReplacer(key, value) {
  // Felder redigieren, die wie Geheimnisse oder PII aussehen
  if (key === "apiKey") return "[REDACTED]"
  if (key === "email") return value.replace(/(?<=.{2}).+(?=@)/, "***")
  return value
}

console.log(JSON.stringify(auditRecord, safeReplacer, 2))
// {
//   "requestId": "req_7d2e91",
//   "user": { "id": "usr_4421", "email": "l.***@beispiel.de", "apiKey": "[REDACTED]" },
//   "action": "update_billing",
//   "timestamp": "2026-03-10T14:22:00.000Z",
//   "durationMs": 87
// }
Hinweis:Die Replacer-Funktion wird mit this aufgerufen, das auf das Objekt mit dem aktuellen Schlüssel zeigt. Der allererste Aufruf übergibt einen leeren String als Schlüssel und den gesamten zu serialisierenden Wert — gib ihn unverändert zurück, um mit der normalen Serialisierung fortzufahren.

Umgang mit nicht serialisierbaren Typen

Nicht alle JavaScript-Werte lassen sich sauber auf JSON abbilden. Zu wissen, wie sich jeder Typ verhält, verhindert stillen Datenverlust und unerwartete Laufzeitfehler im Produktionscode.

Date — Automatisch über toJSON()

Date-Objekte implementieren eine toJSON()-Methode, die einen ISO 8601-String zurückgibt. JSON.stringify() ruft toJSON() automatisch vor der Serialisierung auf, sodass kein benutzerdefinierter Umgang erforderlich ist.

JavaScript — Date serialization
const webhook = {
  eventType: "payment.succeeded",
  occurredAt: new Date("2026-03-10T14:22:00Z"),
  processedAt: new Date()
}

JSON.stringify(webhook, null, 2)
// {
//   "eventType": "payment.succeeded",
//   "occurredAt": "2026-03-10T14:22:00.000Z",
//   "processedAt": "2026-03-10T14:22:01.347Z"
// }

// Jedes Objekt mit einer toJSON()-Methode wird gleich behandelt:
const custom = { toJSON: () => "custom-value", hidden: 42 }
JSON.stringify(custom) // '"custom-value"'

Custom Classes — toJSON() implementieren

Jede Klasse kann eine toJSON()-Methode implementieren, und JSON.stringify() ruft sie automatisch während der Serialisierung auf. Das ist sauberer als ein globaler Replacer für Domain-Typen, die in der gesamten Codebasis vorkommen.

JavaScript — custom toJSON()
class Money {
  constructor(amount, currency) {
    this.amount = amount
    this.currency = currency
  }
  toJSON() {
    // Wird automatisch von JSON.stringify aufgerufen
    return { amount: this.amount, currency: this.currency, formatted: `${this.currency} ${this.amount.toFixed(2)}` }
  }
}

class OrderId {
  constructor(id) { this.id = id }
  toJSON() { return this.id }  // Als einfachen String serialisieren
}

const invoice = {
  invoiceId: new OrderId('inv_8f2a91bc'),
  subtotal: new Money(199.00, 'EUR'),
  tax:      new Money(15.92, 'EUR'),
  issuedAt: new Date('2026-03-10T14:22:00Z')
}

JSON.stringify(invoice, null, 2)
// {
//   "invoiceId": "inv_8f2a91bc",
//   "subtotal": { "amount": 199, "currency": "EUR", "formatted": "EUR 199.00" },
//   "tax": { "amount": 15.92, "currency": "EUR", "formatted": "EUR 15.92" },
//   "issuedAt": "2026-03-10T14:22:00.000Z"
// }
Hinweis:toJSON() hat Vorrang vor der Replacer-Funktion. Sind beide vorhanden, wird toJSON() zuerst ausgeführt — der Replacer erhält den bereits konvertierten Wert, nicht die ursprüngliche Klasseninstanz.

BigInt — TypeError ohne Replacer

JavaScript — BigInt replacer
// Das wirft: TypeError: Do not know how to serialize a BigInt
// JSON.stringify({ sessionId: 9007199254741234n })

// Lösung: BigInt im Replacer in einen String konvertieren
function bigIntReplacer(_key, value) {
  return typeof value === 'bigint' ? value.toString() : value
}

const metrics = {
  requestCount: 9007199254741234n,  // überschreitet Number.MAX_SAFE_INTEGER
  service: "ingestion-worker",
  region: "eu-central-1"
}

JSON.stringify(metrics, bigIntReplacer, 2)
// {
//   "requestCount": "9007199254741234",
//   "service": "ingestion-worker",
//   "region": "eu-central-1"
// }

Zirkuläre Referenzen — TypeError ohne Seen-Set

JavaScript — circular reference replacer
// Das wirft: TypeError: Converting circular structure to JSON
// const node = { id: "n1" }; node.self = node; JSON.stringify(node)

// Lösung: gesehene Objekte mit einem WeakSet verfolgen
function circularReplacer() {
  const seen = new WeakSet()
  return function (_key, value) {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) return '[Circular]'
      seen.add(value)
    }
    return value
  }
}

const parent = { id: "node_parent", label: "root" }
const child  = { id: "node_child", parent }
parent.child = child  // zirkulär

JSON.stringify(parent, circularReplacer(), 2)
// {
//   "id": "node_parent",
//   "label": "root",
//   "child": { "id": "node_child", "parent": "[Circular]" }
// }

// Alternativ: npm install flatted
// import { stringify } from 'flatted'
// stringify(parent)  // behandelt zirkuläre Referenzen nativ

JSON.stringify() Parameter-Referenz

Alle drei Parameter werden in jeder modernen JavaScript-Laufzeitumgebung gut unterstützt. Die Standardwerte erzeugen kompaktes, einzeiliges JSON — übergib Parameter explizit für lesbare Ausgabe.

Parameter
Type
Default
Beschreibung
value
any
Der zu serialisierende Wert. Objekte, Arrays, Strings, Zahlen, Booleans und null werden nativ unterstützt.
replacer
function | Array<string | number> | null
null
Schlüssel/Wert-Paare filtern oder transformieren. Array = Whitelist der einzuschließenden Schlüssel. Funktion = wird für jedes Schlüssel/Wert-Paar aufgerufen.
space
number | string | null
null
Einrückung. Zahl = Leerzeichen pro Ebene (max. 10). String = wörtliche Einrückung (z.B. "\t"). null oder 0 = kompakte Ausgabe.

JSON aus einer Datei und API-Antwort formatieren

In Node.js (18+) musst du oft eine JSON-Konfigurationsdatei neu formatieren oder eine API-Antwort für das Debugging pretty-printen. Beide Muster verwenden denselben zweistufigen Ansatz: den Rohtext mit JSON.parse() parsen, dann mit JSON.stringify() neu serialisieren.

Eine JSON-Konfigurationsdatei lesen und neu schreiben

Node.js 18+ — reformat a JSON file (ESM)
import { readFileSync, writeFileSync } from 'fs'

try {
  const raw = readFileSync('./config/database.json', 'utf8')
  const config = JSON.parse(raw)
  writeFileSync('./config/database.json', JSON.stringify(config, null, 2))
  console.log('Konfiguration erfolgreich neu formatiert')
} catch (err) {
  console.error('Fehler beim Neu-Formatieren der Konfiguration:', err.message)
  // JSON.parse wirft SyntaxError, wenn die Datei ungültiges JSON enthält
  // readFileSync wirft ENOENT, wenn die Datei nicht existiert
}

Asynchrones Datei-Reformat (fs/promises)

Node.js 18+ — async file reformat
import { readFile, writeFile } from 'fs/promises'

async function reformatJson(filePath) {
  const raw = await readFile(filePath, 'utf8')
  const parsed = JSON.parse(raw)
  const formatted = JSON.stringify(parsed, null, 2)
  await writeFile(filePath, formatted, 'utf8')
  return { keys: Object.keys(parsed).length }
}

// Verwendung
const { keys } = await reformatJson('./config/feature-flags.json')
console.log(`${keys} Top-Level-Schlüssel neu formatiert`)

JSON aus einer fetch()-Antwort pretty-printen

Wenn du einen API-Client in Node.js 18+ oder dem Browser entwickelst oder debuggst, ist das Pretty-Printing des Antwort-Body der schnellste Weg, um zu verstehen, was der Server zurückgegeben hat. Das Standardmuster ist response.json() (geparster Objekt) in JSON.stringify(). Benötigst du zuerst den Raw-String — zum Beispiel um einen Hash zu berechnen oder ihn wörtlich zu loggen — verwende response.text() dann JSON.parse().

JavaScript — fetch + pretty print (Node.js 18+ or browser)
// Muster 1: response.json() → pretty print
async function debugEndpoint(url) {
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.API_TOKEN}` }
  })
  if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`)

  const data = await res.json()
  console.log(JSON.stringify(data, null, 2))
}

await debugEndpoint('https://api.stripe.com/v1/charges?limit=3')
JavaScript — response.text() when you need the raw string first
// Muster 2: response.text() → parse → format
// Nützlich, wenn du die Rohantwort UND die pretty-geprinte Version loggen möchtest
async function inspectRawResponse(url) {
  const res = await fetch(url)
  const raw = await res.text()

  console.log('Länge der Rohantwort:', raw.length)
  try {
    const parsed = JSON.parse(raw)
    console.log('Formatiert:')
    console.log(JSON.stringify(parsed, null, 2))
  } catch {
    console.error('Antwort ist kein gültiges JSON:', raw.slice(0, 200))
  }
}

Pretty Printing über die Kommandozeile

Node.js bringt genug Funktionalität mit, um JSON vom Terminal aus pretty-printen zu können, ohne zusätzliche Tools. Diese Einzeiler sind in CI-Skripten, Deployment-Pipelines und Shell-Aliasen nützlich. Für noch schnellere interaktive Nutzung installiere jq — den de-facto-Standard für JSON-Manipulation auf der Kommandozeile.

bash — pretty print a JSON file with Node.js
# package.json mit node -p (print) pretty-printen
node -p "JSON.stringify(require('./package.json'), null, 2)"

# Aus stdin pretty-printen (pipe-freundlich, funktioniert in CI)
echo '{"port":3000,"env":"production"}' | node -e "
  const d = require('fs').readFileSync(0, 'utf8')
  console.log(JSON.stringify(JSON.parse(d), null, 2))
"

# Eine gespeicherte API-Antwort pretty-printen
cat api-response.json | node -e "
  process.stdin.setEncoding('utf8')
  let s = ''
  process.stdin.on('data', c => s += c)
  process.stdin.on('end', () => console.log(JSON.stringify(JSON.parse(s), null, 2)))
"
bash — universal alternatives
# Python-Fallback (vorinstalliert auf macOS und den meisten Linux-Distributionen)
cat api-response.json | python3 -m json.tool

# jq — schnellstes und funktionsreichstes Tool (brew install jq / apt install jq)
cat api-response.json | jq .

# jq — in einem Schritt pretty-printen und filtern
cat api-response.json | jq '.data.users[] | {id, email}'
Hinweis:Wenn Node.js im ESM-Modus ausgeführt wird (z.B. mit "type": "module" in package.json), ist require() in Einzeilern nicht verfügbar. Verwende --input-type=module und fs.readFileSync stattdessen oder wechsle zu node -e mit einem CommonJS-Snippet wie oben gezeigt.

Wenn du gar nicht im Terminal bist — du fügst eine Postman-Antwort oder eine Log-Datei ein — ermöglicht dir der JSON Formatter von ToolDeck das Einfügen, Formatieren und Kopieren in einem Schritt mit Syntaxhervorhebung und eingebauter Validierung.

Hochleistungs-Alternative — fast-json-stringify

fast-json-stringify generiert eine dedizierte Serialisierungsfunktion aus einem JSON Schema. Da es die Form der Daten im Voraus kennt, kann es Typprüfungen überspringen und String-Konkatenation statt rekursivem Abstieg verwenden — Benchmarks zeigen typischerweise einen 2–5×-Durchsatzvorteil gegenüber JSON.stringify() bei großen, repetitiven Payloads. Ich verwende es in hochfrequentierten API-Routen, wo Serialisierungskosten in Profiler-Traces auftauchen.

bash
npm install fast-json-stringify
JavaScript — fast-json-stringify for telemetry events
import fastJson from 'fast-json-stringify'

const serializeTelemetryEvent = fastJson({
  title: 'TelemetryEvent',
  type: 'object',
  properties: {
    eventId:   { type: 'string' },
    service:   { type: 'string' },
    severity:  { type: 'string', enum: ['info', 'warn', 'error'] },
    latencyMs: { type: 'integer' },
    timestamp: { type: 'string' },
    region:    { type: 'string' }
  },
  required: ['eventId', 'service', 'severity', 'latencyMs', 'timestamp']
})

const event = {
  eventId:   'evt_3c7f9a2b',
  service:   'checkout-api',
  severity:  'warn',
  latencyMs: 342,
  timestamp: new Date().toISOString(),
  region:    'eu-central-1'
}

const json = serializeTelemetryEvent(event)
// '{"eventId":"evt_3c7f9a2b","service":"checkout-api","severity":"warn",...}'
Hinweis:fast-json-stringify ist für die Produktions-Serialisierung strukturierter Daten konzipiert — es erzeugt immer kompakte Ausgaben (kein Pretty-Printing). Für menschenlesbare Ausgaben während der Entwicklung verwende JSON.stringify(data, null, 2) wie gewohnt.

Terminal-Ausgabe mit Syntax-Highlighting

Node.js' eingebautes util.inspect() erzeugt farbige, für Menschen lesbare Ausgaben, die für die Terminal-Anzeige optimiert sind. Es behandelt zirkuläre Referenzen und BigInt nativ und rendert verschachtelte Objekte rekursiv bis zu beliebiger Tiefe. Die Ausgabe ist kein gültiges JSON — sie verwendet JavaScript-Syntax (z.B. true statt true, rendert aber Funktionen und Symbols anstatt sie auszulassen), was es ideal für Node.js-Debugging-Skripte, aber ungeeignet für API-Antworten oder Dateiausgaben macht.

Node.js 18+ — util.inspect with colors
import { inspect } from 'util'

const payload = {
  requestId: "req_7d2e91",
  user: { id: "usr_4421", roles: ["admin", "billing"] },
  metadata: { ipAddress: "203.0.113.42", userAgent: "Mozilla/5.0" },
  createdAt: new Date()
}

// depth: null → alle verschachtelten Ebenen aufklappen; colors: true → ANSI-Terminalfarben
console.log(inspect(payload, { colors: true, depth: null }))
Warnung:Verwende util.inspect() nicht für JSON, das in Dateien geschrieben, über das Netzwerk gesendet oder in einer Datenbank gespeichert wird. Seine Ausgabe ist kein gültiges JSON und verursacht Parse-Fehler in jedem nachgelagerten System, das JSON.parse() darauf aufruft. Reserviere es nur für interaktives Terminal-Debugging.

Arbeiten mit großen JSON-Dateien

JSON.parse() lädt die gesamte Datei in den Speicher, bevor sie geparst wird — für kleine Payloads in Ordnung, aber unpraktisch für Dateien über 50–100 MB wie Datenbankexporte, Anwendungs-Log-Dumps oder Analyse-Batches. Für diese Fälle ermöglichen Node.js Streams und die stream-json-Bibliothek die Verarbeitung von Datensätzen einzeln, ohne den Heap zu sprengen.

Streaming-Parsing mit stream-json

bash
npm install stream-json
Node.js 18+ — stream-json for large arrays
import { pipeline } from 'stream/promises'
import { createReadStream } from 'fs'
import { parser } from 'stream-json'
import { streamArray } from 'stream-json/streamers/StreamArray.js'

// events.json = Array mit Millionen von Objekten — wird nie vollständig in den Speicher geladen
await pipeline(
  createReadStream('./events.json'),
  parser(),
  streamArray(),
  async function* (source) {
    for await (const { value: event } of source) {
      if (event.severity === 'error') {
        console.log(JSON.stringify(event, null, 2))
      }
    }
  }
)

NDJSON / JSON Lines — Keine zusätzlichen Abhängigkeiten

NDJSON (Newline Delimited JSON) speichert ein JSON-Objekt pro Zeile und ist in Kafka-Exporten, BigQuery-Ausgaben und strukturierten Log-Pipelines verbreitet. Node.js' eingebautes readline verarbeitet es ohne Drittanbieter-Pakete.

Node.js 18+ — NDJSON with readline
import { createReadStream } from 'fs'
import { createInterface } from 'readline'

// Format: ein JSON-Objekt pro Zeile (Logs, Kafka-Exporte, BigQuery)
const rl = createInterface({
  input: createReadStream('./logs.ndjson'),
  crlfDelay: Infinity
})

for await (const line of rl) {
  if (!line.trim()) continue
  const entry = JSON.parse(line)
  if (entry.level === 'error') {
    console.log(JSON.stringify(entry, null, 2))
  }
}
Hinweis:Wechsle von JSON.parse() zu Streaming, wenn deine JSON-Datei 50–100 MB überschreitet oder wenn du einen unbegrenzten Stream verarbeitest (Kafka, Log-Pipeline). Für NDJSON / JSON Lines verwende readline — es erfordert keine zusätzlichen Abhängigkeiten.

Häufige Fehler

Diese vier Fehler tauchen immer wieder in Code-Reviews und Produktions-Bug-Reports auf. Jeder involviert ein subtiles Verhalten von JSON.stringify(), das leicht zu übersehen und im Nachhinein schwer zu debuggen ist.

Vergessen, dass undefined-Werte stillschweigend entfernt werden

Problem: Objekt-Properties mit undefined-Werten werden vollständig aus der JSON-Ausgabe ausgelassen — es gibt keine Warnung oder keinen Fehler. Das verursacht unsichtbaren Datenverlust, wenn optionale Felder im Objekt vorhanden sind.

Lösung: Verwende null für absichtlich fehlende Werte, die in der serialisierten Ausgabe erscheinen müssen. Reserviere undefined nur für Felder, die aus dem JSON ausgeschlossen werden sollen.

Before · JavaScript
After · JavaScript
const userProfile = {
  userId: "usr_4421",
  displayName: "Lukas Bauer",
  avatarUrl: undefined,   // verschwindet stillschweigend
  bio: undefined          // verschwindet stillschweigend
}

JSON.stringify(userProfile, null, 2)
// { "userId": "usr_4421", "displayName": "Lukas Bauer" }
// avatarUrl und bio sind weg — keine Warnung
const userProfile = {
  userId: "usr_4421",
  displayName: "Lukas Bauer",
  avatarUrl: null,   // explizit abwesend — erscheint in der Ausgabe
  bio: null          // explizit abwesend — erscheint in der Ausgabe
}

JSON.stringify(userProfile, null, 2)
// {
//   "userId": "usr_4421",
//   "displayName": "Lukas Bauer",
//   "avatarUrl": null,
//   "bio": null
// }
BigInt wirft TypeError

Problem: Ein BigInt-Wert an JSON.stringify() zu übergeben, wirft zur Laufzeit einen TypeError. Das ist ein harter Absturz, keine stille Auslassung — er tritt in der Produktion auf, wenn ein numerisches Feld Number.MAX_SAFE_INTEGER überschreitet.

Lösung: Verwende eine Replacer-Funktion, die BigInt-Werte vor der Serialisierung in Strings konvertiert. Alternativ kann BigInt vor der Übergabe an JSON.stringify in String oder Number umgewandelt werden.

Before · JavaScript
After · JavaScript
const session = {
  sessionId: 9007199254741234n,  // BigInt-Literal
  userId: "usr_4421",
  startedAt: "2026-03-10T14:00:00Z"
}

JSON.stringify(session, null, 2)
// Uncaught TypeError: Do not know how to serialize a BigInt
function bigIntReplacer(_key, value) {
  return typeof value === 'bigint' ? value.toString() : value
}

const session = {
  sessionId: 9007199254741234n,
  userId: "usr_4421",
  startedAt: "2026-03-10T14:00:00Z"
}

JSON.stringify(session, bigIntReplacer, 2)
// {
//   "sessionId": "9007199254741234",
//   "userId": "usr_4421",
//   "startedAt": "2026-03-10T14:00:00Z"
// }
Absturz durch zirkuläre Referenzen

Problem: Objekte, die auf sich selbst verweisen — häufig in DOM-Bäumen, verketteten Listen und manchen ORM-Ergebnismengen — werfen einen TypeError, wenn sie an JSON.stringify() übergeben werden. Der Fehler tritt erst zur Serialisierungszeit auf, oft weit entfernt von der Stelle, an der die zirkuläre Referenz erstellt wurde.

Lösung: Verwende eine Replacer-Funktion mit einem WeakSet, um zirkuläre Referenzen zu erkennen und zu ersetzen, oder installiere die flatted-Bibliothek als Drop-in-Ersatz, der zirkuläre Strukturen nativ behandelt.

Before · JavaScript
After · JavaScript
const dept = { id: "dept_eng", name: "Engineering" }
const team = { id: "team_frontend", dept }
dept.teams = [team]  // zirkulär: dept → team → dept

JSON.stringify(dept, null, 2)
// Uncaught TypeError: Converting circular structure to JSON
import { stringify } from 'flatted'  // npm install flatted

const dept = { id: "dept_eng", name: "Engineering" }
const team = { id: "team_frontend", dept }
dept.teams = [team]

// flatted behandelt zirkuläre Refs — Hinweis: Ausgabe ist flatted-Format, kein Standard-JSON
stringify(dept)

// Oder WeakSet-basierten Replacer verwenden für Standard-JSON-Ausgabe:
function circularReplacer() {
  const seen = new WeakSet()
  return (_key, value) => {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) return '[Circular]'
      seen.add(value)
    }
    return value
  }
}
JSON.stringify(dept, circularReplacer(), 2)
space > 10 verwenden (wird stillschweigend begrenzt)

Problem: Ein space-Wert größer als 10 an JSON.stringify() zu übergeben, wirft keinen Fehler — der Wert wird stillschweigend auf 10 begrenzt. Entwickler, die 20 Leerzeichen pro Einrückung für tiefe Verschachtelung erwarten, erhalten nur 10, was zu unerwarteter Formatierung in generierten Dateien führt.

Lösung: Die maximale Einrückung beträgt 10 Leerzeichen. Für tiefe Strukturen bevorzuge 2-Leerzeichen-Einrückung (die häufigste Konvention in JavaScript-Projekten) und verlass dich auf einklappbare Editoren für die Navigation.

Before · JavaScript
After · JavaScript
const deepConfig = { server: { tls: { certs: { primary: "/etc/ssl/api.pem" } } } }

// 20-Leerzeichen-Einrückung erwartet — aber space wird auf 10 begrenzt
JSON.stringify(deepConfig, null, 20)
// Gleiche Ausgabe wie JSON.stringify(deepConfig, null, 10)
// Kein Fehler, keine Warnung — stillschweigend abgeschnitten
const deepConfig = { server: { tls: { certs: { primary: "/etc/ssl/api.pem" } } } }

// 2 (die meisten Projekte) oder 4 Leerzeichen verwenden — niemals 10 überschreiten
JSON.stringify(deepConfig, null, 2)
// {
//   "server": {
//     "tls": {
//       "certs": {
//         "primary": "/etc/ssl/api.pem"
//       }
//     }
//   }
// }

JSON.stringify vs. Alternativen — Schnellvergleich

Verschiedene Situationen erfordern verschiedene Tools. JSON.stringify mit einem Replacer deckt die meisten Produktionsanwendungsfälle ohne Abhängigkeiten ab. util.inspect ist die richtige Wahl für schnelles Terminal-Debugging, wenn du farbige Ausgaben brauchst und kein gültiges JSON benötigst. fast-json-stringify lohnt sich in hochdurchsatzfähigen Routen, wo Profiling Serialisierungskosten zeigt; für alles andere ist der Overhead der Schema-Pflege es nicht wert.

Methode
Pretty Output
Valid JSON
Non-ASCII
Custom Types
Circular Refs
Installation
JSON.stringify
⚠️ via replacer
✗ (throws)
Nein
JSON.stringify + replacer
✅ volle Kontrolle
Nein
util.inspect
✅ nativ
Nein (Node built-in)
fast-json-stringify
❌ schema-only
npm install
flatted
✗ (custom format)
✅ nur circular
npm install
jq (CLI)
N/A
N/A
System install

Häufig gestellte Fragen

Wie formatiere ich JSON in JavaScript?

Rufe JSON.stringify(data, null, 2) auf — das dritte Argument steuert die Einrückung. Übergib 2 oder 4 für Leerzeichen oder "\t" für Tabs. Kein Import oder keine Installation erforderlich: JSON ist ein globales Objekt in jeder JavaScript-Umgebung, einschließlich Browser und Node.js.

JavaScript
const config = { host: "api.payments.internal", port: 8443, tls: true }
console.log(JSON.stringify(config, null, 2))
// {
//   "host": "api.payments.internal",
//   "port": 8443,
//   "tls": true
// }

Was bewirkt der `space`-Parameter in JSON.stringify()?

Der space-Parameter steuert die Einrückung in der Ausgabe. Übergib eine Zahl (1–10) für diese Anzahl von Leerzeichen pro Ebene oder einen String wie "\t" für ein Tab-Zeichen. Werte über 10 werden stillschweigend auf 10 begrenzt. null, 0 oder das Weglassen des Parameters erzeugt kompaktes einzeiliges JSON.

JavaScript
const data = { service: "payments", version: 3, active: true }

JSON.stringify(data, null, 2)   // 2 Leerzeichen Einrückung
JSON.stringify(data, null, 4)   // 4 Leerzeichen Einrückung
JSON.stringify(data, null, '\t') // Tab-Einrückung
JSON.stringify(data)            // kompakt: {"service":"payments","version":3,"active":true}

Warum gibt JSON.stringify() für manche Werte undefined zurück?

JSON.stringify lässt Objekteigenschaften stillschweigend aus, deren Werte undefined, Funktionen oder Symbols sind — diese Typen haben keine JSON-Darstellung. Ist der oberste Wert selbst undefined, gibt die Funktion undefined zurück (nicht den String "undefined"). Verwende null statt undefined für optionale Felder, die in der Ausgabe erscheinen müssen.

JavaScript
const event = {
  traceId: "tr_9a2f",
  handler: () => {},        // Funktion — wird ausgelassen
  requestId: undefined,     // undefined — wird ausgelassen
  sessionId: Symbol("s"),   // Symbol — wird ausgelassen
  status: "ok"
}
JSON.stringify(event, null, 2)
// { "traceId": "tr_9a2f", "status": "ok" }

Wie gehe ich mit Date-Objekten beim JSON-Formatieren um?

Date-Objekte haben eine eingebaute toJSON()-Methode, die einen ISO 8601-String zurückgibt, sodass JSON.stringify sie automatisch verarbeitet. Du brauchst keinen benutzerdefinierten Replacer für Datumsangaben — der serialisierte Wert ist ein String wie "2026-03-10T14:22:00.000Z".

JavaScript
const order = {
  orderId: "ord_8f2a91bc",
  placedAt: new Date("2026-03-10T14:22:00Z"),
  total: 42.98
}
JSON.stringify(order, null, 2)
// {
//   "orderId": "ord_8f2a91bc",
//   "placedAt": "2026-03-10T14:22:00.000Z",
//   "total": 42.98
// }

Wie formatiere ich einen JSON-String (kein Objekt) in JavaScript?

Parse den String zuerst mit JSON.parse(), dann serialisiere ihn erneut mit JSON.stringify(). Die beiden Aufrufe können für schnelles Debugging in einer Zeile verkettet werden.

JavaScript
const raw = '{"endpoint":"/api/v2/users","timeout":30,"retry":true}'
const formatted = JSON.stringify(JSON.parse(raw), null, 2)
console.log(formatted)
// {
//   "endpoint": "/api/v2/users",
//   "timeout": 30,
//   "retry": true
// }

Kann ich JSON.stringify() im Browser verwenden?

Ja. JSON ist ein eingebautes Global in jedem modernen Browser seit IE8 — keine Script-Tags oder Imports nötig. Öffne die DevTools-Konsole und rufe JSON.stringify() direkt auf. Es funktioniert identisch zur Node.js-Version, mit der gleichen Parameter-Signatur und den gleichen Einschränkungen bei BigInt und zirkulären Referenzen.

JavaScript
// Funktioniert in Chrome, Firefox, Safari, Edge — keine Imports nötig
const payload = { userId: "usr_7b3c", action: "checkout", cart: ["SKU-001", "SKU-002"] }
copy(JSON.stringify(payload, null, 2)) // copy() ist ein DevTools-Helfer

JavaScript gibt dir volle Kontrolle — Replacer-Funktionen, eigenes toJSON(), Verarbeitung großer Dateien in Node.js. Wenn du nur einen formatierten Ausschnitt prüfen oder teilen möchtest, ist der JSON Formatter von ToolDeck der schnellste Weg: JSON einfügen und ein formatiertes, hervorgehobenes Ergebnis ohne jedes Environment-Setup erhalten.

Verwandte Tools

Auch verfügbar in:PythonGoBash
AC
Alex ChenFront-end & Node.js Developer

Alex is a front-end and Node.js developer with extensive experience building web applications and developer tooling. He is passionate about web standards, browser APIs, and the JavaScript ecosystem. In his spare time he contributes to open-source projects and writes about modern JavaScript patterns, performance optimisation, and everything related to the web platform.

MW
Marcus WebbTechnischer Prüfer

Marcus specialises in JavaScript performance, build tooling, and the inner workings of the V8 engine. He has spent years profiling and optimising React applications, working on bundler configurations, and squeezing every millisecond out of critical rendering paths. He writes about Core Web Vitals, JavaScript memory management, and the tools developers reach for when performance really matters.