← Todos los artículos

Cómo serializar JSON con JSON.stringify

JSON.stringify convierte un valor en una cadena JSON. Aprende los argumentos space y replacer, el hook toJSON y los valores que descarta o sobre los que lanza.

JSON.stringify() convierte un valor JavaScript en una cadena JSON —— para enviarlo en el cuerpo de una petición, guardarlo en un fichero o almacenarlo en localStorage. Parece simple, pero sus tres argumentos, su manejo de valores especiales y el hook toJSON hacen tropezar a los desarrolladores sin cesar. Esta guía cubre todo lo que hace JSON.stringify(), los equivalentes en otros lenguajes y las trampas a evitar.

Qué hace JSON.stringify

Recorre un valor recursivamente y produce una cadena JSON conforme a la especificación. La salida por defecto es compacta, sin espacios adicionales:

const user = { name: "Ada", age: 36, active: true };

JSON.stringify(user);
// '{"name":"Ada","age":36,"active":true}'

Como siempre emite JSON válido, nunca construyas cadenas JSON a mano con concatenación o template literals —— hacerlo es la causa número uno de errores [object Object] y errores de comas finales.

Los tres argumentos

JSON.stringify(value, replacer, space) acepta un valor y dos argumentos opcionales que la mayoría no usa nunca —— pero son potentes.

space —— pretty-print

El tercer argumento controla la indentación. Pasa un número para esos espacios, o una cadena como '\t' para tabuladores:

JSON.stringify(user, null, 2);
// {
//   "name": "Ada",
//   "age": 36,
//   "active": true
// }

Así es como se hace pretty-print de JSON en código —— ver Cómo formatear JSON. Omite el argumento (o pasa 0) para minificar; ver Cómo minificar JSON.

replacer —— filtrar y transformar

El segundo argumento puede ser un array de claves a incluir o una función que transforma cada valor:

// Lista blanca: solo sobreviven estas claves
JSON.stringify(user, ['name', 'active']);
// '{"name":"Ada","active":true}'

// Función: enmascara un campo, descarta otro
JSON.stringify(
  { name: "Ada", password: "secret", token: "abc" },
  (key, value) => {
    if (key === 'password') return '[REDACTED]';
    if (key === 'token') return undefined; // devolver undefined omite la clave
    return value;
  },
);
// '{"name":"Ada","password":"[REDACTED]"}'

El hook toJSON

Si un valor tiene un método toJSON(), JSON.stringify() lo llama y serializa el valor devuelto en su lugar. Por eso los objetos Date se convierten automáticamente en cadenas ISO:

JSON.stringify({ when: new Date('2026-05-24T00:00:00Z') });
// '{"when":"2026-05-24T00:00:00.000Z"}'  ← Date.prototype.toJSON ejecutado

// Tu propio toJSON para serialización personalizada
class Money {
  constructor(cents) { this.cents = cents; }
  toJSON() { return (this.cents / 100).toFixed(2); }
}
JSON.stringify({ price: new Money(1999) });
// '{"price":"19.99"}'

Qué se descarta o se convierte

JSON solo tiene seis tipos, así que los valores JavaScript sin equivalente JSON se descartan en silencio o se convierten —— fuente habitual de bugs en round-trip:

Valor JavaScriptResultado de JSON.stringify
undefined (en objeto)clave omitida
undefined (en array)null
funciónomitida (objeto) / null (array)
Symbolomitido
NaN, Infinitynull
Datecadena ISO (vía toJSON)
BigIntlanza TypeError

Para la lista completa de cómo difiere JSON de los objetos JavaScript, ver JSON vs objetos JavaScript.

Trampas comunes

Las referencias circulares lanzan

const a = {};
a.self = a;
JSON.stringify(a);
// TypeError: Converting circular structure to JSON

// Solución: un replacer que rastree objetos vistos, o reestructura los datos

BigInt no es compatible

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

// Solución: convertir a string primero, o añadir un replacer
JSON.stringify({ id: 9007199254740993n }, (k, v) =>
  typeof v === 'bigint' ? v.toString() : v
);

Los enteros grandes pierden precisión en el round-trip

Los números por encima de 253 no pueden representarse de forma exacta. Si stringifyas y luego parseas un ID entero grande, puede cambiar. Guarda esos IDs como cadenas.

APIs cercanas: structuredClone, el reviver y Stable Stringify

  • structuredClone —— para copias profundas en memoria, no uses JSON.parse(JSON.stringify(x)). structuredClone maneja Date, Map, Set, ArrayBuffer y referencias circulares de forma nativa y es mucho más rápido.
  • El argumento reviver de JSON.parse es el reflejo del replacer de aquí. Úsalos en pareja cuando necesites round-trip sin pérdida para tipos que JSON no modela —— p. ej. codifica Date como cadena ISO en replacer y rehidrátalo en reviver.
  • Librerías stable-stringify (p. ej. json-stable-stringify, fast-json-stable-stringify) —— producen la misma cadena independientemente del orden de inserción de las claves. Úsalas cuando la salida se hashee, firme o compare como texto (ver RFC 8785 / JCS para la versión formal).

Stringify en otros lenguajes

# Python
import json
json.dumps({"name": "Ada"})                       # compacto
json.dumps({"name": "Ada"}, indent=2)             # pretty
json.dumps({"name": "Ada"}, separators=(',', ':')) # minificado

// Go
import "encoding/json"
b, _ := json.Marshal(map[string]string{"name": "Ada"})

// Ruby
require 'json'
{ name: "Ada" }.to_json

Stringify de JSON en tu navegador

¿Necesitas escapar un valor JSON a un literal de cadena —— para incrustarlo en código, una columna de BD o un comando de shell? La herramienta JSON Stringify de fixjson lo hace al instante, en tu navegador, sin enviar datos a ningún servidor.

Preguntas frecuentes

¿Cómo hago pretty-print con JSON.stringify?

Pasa un tercer argumento: JSON.stringify(value, null, 2) para 2 espacios o '\t' para tabuladores. Ver Cómo formatear JSON.

¿Por qué JSON.stringify descarta algunas de mis propiedades?

Las propiedades con valores undefined, función o Symbol se omiten porque JSON no tiene representación para ellos. Usa un replacer o conviértelos antes.

¿Cómo hago stringify de un valor con BigInt?

JSON.stringify() lanza con BigInt. Proporciona un replacer que llame a .toString() sobre los valores bigint y parsealos deliberadamente al otro lado.

¿Cuál es la diferencia entre JSON.stringify y JSON.parse?

stringify convierte un valor en una cadena JSON; parse convierte una cadena JSON en un valor. Son inversos. Para trampas del parseo, ver Manejar JSON roto en JavaScript.

¿Cómo hago JSON.stringify de un Map o Set?

Por defecto ambos se serializan como "{}" —— un Map no tiene propiedades propias enumerables y un Set se stringifya como objeto vacío. Conviértelos antes a una forma JSON-friendly (o vía un replacer):

// Map → array de pares [key, value] (round-trippable)
JSON.stringify([...myMap]);
// o con un replacer:
JSON.stringify({ data: myMap }, (k, v) =>
  v instanceof Map ? Object.fromEntries(v) :
  v instanceof Set ? [...v] : v
);

De vuelta, reconstruye con new Map(arr) / new Set(arr) en un reviver de JSON.parse, ya que el JSON puro no tiene tipos Map/Set.

Pruébalo ahora