Cómo Formatear JSON en JavaScript — 5 Métodos
JSON está en todas partes: respuestas de API, archivos de configuración, exportaciones de bases de datos, pipelines de logs. Pero la salida JSON bruta suele ser un blob compacto — sin saltos de línea, sin indentación, con las claves en el orden en que el serializador las escupe. Eso hace que la depuración sea dolorosa y la colaboración más difícil de lo necesario.
JavaScript te ofrece varias formas de formatear JSON, desde el integrado JSON.stringify hasta bibliotecas de streaming para archivos demasiado grandes para cargarlos en memoria. Esta guía repasa cinco métodos prácticos, cubriendo los casos más comunes y los casos límite que sorprenden a los desarrolladores.
Método 1: JSON.stringify con Indentación
El enfoque más sencillo ya está integrado en el lenguaje. JSON.stringify acepta tres argumentos: el valor a serializar, un replacer (más sobre eso en el Método 2), y un parámetro space que controla la indentación.
const data = {
name: "Alice",
role: "engineer",
skills: ["JavaScript", "TypeScript", "Node.js"],
active: true,
};
// Indentación de 2 espacios (valor predeterminado común)
console.log(JSON.stringify(data, null, 2));
// Indentación de 4 espacios
console.log(JSON.stringify(data, null, 4));
// Indentación con tabulador
console.log(JSON.stringify(data, null, "\t"));
Con null, 2, la salida tiene este aspecto:
{
"name": "Alice",
"role": "engineer",
"skills": [
"JavaScript",
"TypeScript",
"Node.js"
],
"active": true
}
Dos espacios es la convención más común en proyectos JavaScript — coincide con el valor predeterminado en ESLint, Prettier y la mayoría de las guías de estilo. Cuatro espacios es común en herramientas relacionadas con Python. Cuando space se omite o se establece en 0, la salida es una cadena compacta de una sola línea — ideal para la transmisión por red.
También puedes formatear JSON al instante en el navegador usando la herramienta JSON Formatter — pega JSON sin procesar, obtén la salida con formato legible y copia el resultado sin escribir ningún código.
Método 2: Función Replacer Personalizada
El segundo argumento de JSON.stringify — el replacer — es una función o array que filtra y transforma los valores antes de la serialización. Aquí es donde obtienes control real sobre lo que termina en la salida.
La forma de array es el enfoque más sencillo para la lista blanca de claves:
const user = {
id: 42,
name: "Bob",
password: "s3cr3t",
email: "bob@example.com",
createdAt: new Date(),
};
// Array replacer: incluir solo las claves listadas
const safeJson = JSON.stringify(user, ["id", "name", "email"], 2);
console.log(safeJson);
// {
// "id": 42,
// "name": "Bob",
// "email": "bob@example.com"
// }
La forma de función te da control por valor. Devuelve el valor para incluirlo, devuelve undefined para descartarlo, o devuelve un valor transformado:
function replacer(key, value) {
// Descartar claves que empiezan con guion bajo (convención privada)
if (key.startsWith("_")) return undefined;
// Enmascarar campos sensibles
if (key === "password" || key === "token") return "[REDACTADO]";
// Convertir objetos Date a cadenas ISO explícitamente
if (value instanceof Date) return value.toISOString();
return value;
}
const payload = {
id: 1,
name: "Carol",
password: "hunter2",
_internalFlag: true,
lastLogin: new Date("2026-05-01"),
};
console.log(JSON.stringify(payload, replacer, 2));
// {
// "id": 1,
// "name": "Carol",
// "password": "[REDACTADO]",
// "lastLogin": "2026-05-01T00:00:00.000Z"
// } El replacer se ejecuta recursivamente en cada objeto y array anidados. Este patrón es útil para pipelines de logging donde quieres eliminar credenciales antes de escribir en disco o enviar a un servicio de observabilidad.
Método 3: Formato con Claves Ordenadas
Los objetos JavaScript no garantizan el orden de las claves (aunque V8 y la mayoría de los motores preservan el orden de inserción para claves de cadena). Cuando necesitas una salida determinista — para comparación de diferencias, caché o representaciones canónicas — ordenar las claves alfabéticamente es el paso correcto.
function sortedStringify(value, indent = 2) {
return JSON.stringify(value, sortReplacer, indent);
}
function sortReplacer(key, value) {
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
return Object.keys(value)
.sort()
.reduce((sorted, k) => {
sorted[k] = value[k];
return sorted;
}, {});
}
return value;
}
const config = {
version: "1.0",
author: "Dave",
dependencies: { typescript: "^5.4", eslint: "^9.0", astro: "^5.0" },
name: "my-project",
};
console.log(sortedStringify(config));
// {
// "author": "Dave",
// "dependencies": { "astro": "^5.0", "eslint": "^9.0", "typescript": "^5.4" },
// "name": "my-project",
// "version": "1.0"
// }
Las claves ordenadas significan que los diffs de git muestran solo las líneas que realmente cambiaron, en lugar de reordenaciones arbitrarias de diferentes serializadores. Esto es particularmente útil para package.json y archivos de configuración similares registrados en control de versiones.
Para convertir JSON a otros formatos, la herramienta JSON a YAML y la herramienta JSON a CSV también manejan el ordenamiento de claves en su salida.
Método 4: Formatear desde una Cadena (Parse + Stringify)
En el mundo real, el JSON suele llegar como una cadena — de una respuesta fetch, una lectura de archivo, un portapapeles pegado o una columna TEXT de una base de datos. Primero necesitas analizarla, luego reformatearla. La parte crítica es el manejo adecuado de errores: el JSON inválido lanzará una excepción, y quieres capturarla con elegancia.
function formatJsonString(rawString, indent = 2) {
try {
const parsed = JSON.parse(rawString);
return { ok: true, result: JSON.stringify(parsed, null, indent) };
} catch (err) {
return { ok: false, error: err.message };
}
}
const raw = '{"name":"Eve","scores":[100,95,88],"active":true}';
const { ok, result, error } = formatJsonString(raw);
if (ok) {
console.log(result);
// {
// "name": "Eve",
// "scores": [100, 95, 88],
// "active": true
// }
} else {
console.error("Error de análisis:", error);
}
// Entrada inválida
const bad = '{"name": "Eve", "broken":}';
const r2 = formatJsonString(bad);
// { ok: false, error: "Unexpected token '}'" } Envolver los errores de análisis en un objeto de retorno estructurado hace que esta función sea segura para usar en componentes de UI y scripts de build sin rodear cada llamada con un try/catch. La documentación de MDN para JSON.stringify cubre la especificación completa de parámetros, y el RFC 8259 define cómo luce el JSON válido a nivel de protocolo.
Método 5: Streaming para Archivos Grandes
Los métodos 1–4 cargan toda la estructura JSON en memoria antes de formatearla. Para archivos en el rango de cientos de megabytes o multi-gigabytes, esto bloquea el event loop de Node.js y puede hacer que el proceso se cuelgue completamente.
El enfoque de streaming lee el archivo en trozos y escribe la salida formateada de forma incremental. Para NDJSON (un objeto JSON por línea, común en archivos de log y exportaciones de bases de datos), un enfoque basado en readline funciona sin dependencias extra:
import { createReadStream, createWriteStream } from "node:fs";
import { createInterface } from "node:readline";
async function formatNdjsonFile(inputPath, outputPath) {
const rl = createInterface({
input: createReadStream(inputPath),
crlfDelay: Infinity,
});
const output = createWriteStream(outputPath);
for await (const line of rl) {
if (!line.trim()) continue;
try {
const obj = JSON.parse(line);
output.write(JSON.stringify(obj, null, 2) + "\n---\n");
} catch (e) {
output.write("[Línea JSON inválida: " + e.message + "]\n---\n");
}
}
output.end();
} NDJSON es el formato de streaming más simple: cada línea es un objeto JSON válido y completo. Muchas herramientas de exportación lo soportan precisamente porque es trivialmente streamable. Si controlas el formato de las exportaciones de datos grandes, prefiere NDJSON sobre un único array JSON gigante.
Casos Límite a Tener en Cuenta
Estos son los escenarios donde el formateo JSON estándar falla silenciosamente o lanza excepciones de forma inesperada.
Referencias Circulares
JSON.stringify lanza un TypeError si un objeto se referencia a sí mismo directa o indirectamente. Soluciónalo con un replacer que rastree los objetos visitados usando un WeakSet:
function safeStringify(obj, indent = 2) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) return "[Circular]";
seen.add(value);
}
return value;
}, indent);
}
const a = { name: "circular" };
a.self = a;
console.log(safeStringify(a));
// { "name": "circular", "self": "[Circular]" }
El WeakSet mantiene referencias sin impedir la recolección de basura, lo que evita fugas de memoria en procesos de larga duración.
Valores BigInt
JSON.stringify lanza un TypeError para valores BigInt porque la especificación JSON no tiene un tipo entero de 64 bits. Conviértelos a cadena en tu replacer:
const data = { id: 9007199254740993n, value: 42 };
JSON.stringify(data, (key, value) =>
typeof value === "bigint" ? value.toString() : value
, 2);
// { "id": "9007199254740993", "value": 42 } Valores Map y Set
Map se serializa como un objeto vacío y Set se serializa como un array vacío — no su contenido. Conviértelos explícitamente en un replacer:
const data = {
tags: new Set(["json", "javascript"]),
meta: new Map([["source", "api"]]),
};
JSON.stringify(data, (key, value) => {
if (value instanceof Set) return [...value];
if (value instanceof Map) return Object.fromEntries(value);
return value;
}, 2);
// { "tags": ["json", "javascript"], "meta": { "source": "api" } } Valores undefined
Las propiedades de objetos con valores undefined se descartan silenciosamente. Las posiciones de array con undefined se convierten en null. Usa un replacer para convertir undefined en null cuando necesites preservar todas las claves:
const obj = { a: 1, b: undefined, c: null };
JSON.stringify(obj, null, 2);
// { "a": 1, "c": null } — "b" se descarta silenciosamente
// Solución:
JSON.stringify(obj, (key, value) =>
value === undefined ? null : value
, 2);
// { "a": 1, "b": null, "c": null } Formatea JSON al Instante en el Navegador
Si necesitas formatear un blob JSON ahora mismo sin escribir ningún código, el Formateador JSON de Toova lo hace con un clic — pega JSON sin procesar, obtén la salida con formato legible con indentación de 2 o 4 espacios, y copia el resultado. Sin registro, sin subida de archivos, todo se ejecuta localmente en tu navegador.
Para conversiones entre formatos, JSON a YAML y JSON a CSV siguen el mismo enfoque de privacidad primero — tus datos nunca abandonan tu dispositivo.
Conclusión
Para la mayoría de los casos de uso, JSON.stringify(obj, null, 2) es todo lo que necesitas. Añade una función replacer cuando necesites filtrado, enmascarado o claves ordenadas. Envuelve JSON.parse en un try/catch cuando manejes entrada externa. Recurre al streaming solo cuando el tamaño del archivo hace que el análisis síncrono sea impracticable. Y mantén los casos límite — referencias circulares, BigInt, Map/Set, undefined — en mente cuando trabajes con formas de datos inusuales.