Comparador JSON
Compara dos objetos JSON y visualiza las diferencias resaltadas.
Acerca de la comparación JSON
La comparación JSON (también llamada diff JSON) identifica las diferencias entre dos estructuras JSON. A diferencia de un diff de texto plano, una comparación que entiende JSON conoce las claves y los valores, y puede por tanto indicarte exactamente qué propiedades se han añadido, eliminado o modificado · independientemente del orden de las claves.
Esta herramienta realiza una comparación profunda y recursiva de dos objetos JSON. Gestiona objetos anidados, arrays, cadenas, números, booleanos y valores null. Todo el procesamiento se hace localmente en tu navegador.
Una breve historia de JSON
La biografía de JSON es más corta que la del lenguaje de programación medio y bastante menos dramática. El acrónimo se originó en State Software, Inc., una pequeña compañía que Douglas Crockford y Chip Morningstar fundaron en marzo de 2001 para construir lo que después se llamaría aplicaciones web Ajax. El primer mensaje JSON se envió en abril de 2001, desde un ordenador en el garaje de Morningstar en el Área de la Bahía. Crockford no afirma haber inventado JSON, lo desprendió de la sintaxis de literales de objeto de JavaScript, le dio nombre y montó un sitio web. Adquirió json.org en 2002 y publicó allí una gramática en diagrama ferroviario. Durante cuatro años JSON se propagó por boca a boca y un lento goteo de implementaciones de bibliotecas. En diciembre de 2005, Yahoo! comenzó a ofrecer algunos de sus servicios web en JSON, el momento que la mayoría de los historiadores señalan como la entrada de JSON al mainstream. La estandarización vino en olas: RFC 4627 (julio de 2006), de la pluma del propio Crockford, con estatus informacional en lugar de standards-track; ECMA-404 primera edición (octubre de 2013); RFC 7159 (marzo de 2014), que metió JSON en el Standards Track de la IETF y aflojó la exigencia de que el valor de nivel superior fuera objeto o array. Las versiones actuales son RFC 8259 (diciembre de 2017), ahora Internet Standard STD 90, y ECMA-404 segunda edición (diciembre de 2017). Las dos son intencionalmente idénticas en gramática; el texto IETF añade guía de seguridad e interoperabilidad que el texto Ecma omite deliberadamente.
Dos familias algorítmicas: diff por línea y diff estructural
La informática lleva pensando en diffs desde los años 1970. Douglas McIlroy (el mismo McIlroy que inventó las tuberías Unix) y James W. Hunt escribieron el diff Unix original a principios de los años 1970; se entregó como parte de la 5.ª edición de Unix en 1974, con el algoritmo subyacente documentado en el Bell Labs Computing Science Technical Report #41 en junio de 1976. Hunt-McIlroy se basa en el problema de la subsecuencia común más larga: encontrar la secuencia más larga de líneas que aparece en orden en ambas entradas, y todo lo que no está en esa secuencia es o una eliminación o una inserción. Una década después, Eugene W. Myers publicó «An O(ND) Difference Algorithm and Its Variations» en Algorithmica Vol 1, Issue 2 (1986), replanteando el problema como búsqueda de camino más corto sobre un «grafo de edición», base para una implementación Unix diff más rápida que corría dos a cuatro veces más rápida que su predecesora. Hoy, git diff tiene por defecto un algoritmo histograma en LibXDiff, generalmente más rápido que Myers vainilla y produciendo salida más legible, especialmente alrededor de bloques movidos. Patience diff (Bram Cohen, 2008) es otro refinamiento LCS que prioriza líneas ancla únicas. Todas variaciones sobre un tema: LCS línea por línea, tratando la entrada como una secuencia plana de tokens opacos. Ninguno sabe qué es JSON.
La familia de diff estructural toma un enfoque diferente: recorrer ambas entradas en paralelo, comparando primitivos por igualdad estricta, calculando la unión de claves de objeto (presente-solo-a-la-izquierda es «eliminado», presente-solo-a-la-derecha es «añadido», presente-en-ambos significa recursión), y recorriendo arrays por índice. Para cada posición, recursión. Si un array es más largo, los elementos extra son añadidos o eliminados. Los cambios de tipo (número vs cadena, objeto vs array) se vuelven entradas «tipo cambiado». Este es el algoritmo que jsondiffpatch implementa como caso base, y es el algoritmo que esta herramienta implementa. Su fuerza es que la salida tiene significado: cada cambio reportado tiene una ruta dentro del documento (user.address.city, items[3].price) y semántica clara. Su debilidad es el tercer paso, la comparación de arrays por índice, que produce sin sentidos cada vez que un elemento se inserta cerca del principio de un array largo.
El problema más duro del diff JSON: los arrays
Supongamos que tu JSON «antes» contiene el array ["alpha", "beta", "gamma", "delta"] y tu JSON «después» contiene ["alpha", "new", "beta", "gamma", "delta"]. Un diff ingenuo basado en índice reporta cuatro cambios: índice 1 cambió de «beta» a «new»; índice 2 cambió de «gamma» a «beta»; índice 3 cambió de «delta» a «gamma»; índice 4 añadido «delta». Un humano mirando esto diría que hay un cambio: una sola inserción en el índice 1. Este es el mismo problema LCS que la familia de diff por línea resolvió en los años 1970, aplicado a arrays de valores JSON en lugar de arrays de líneas de texto. jsondiffpatch hace exactamente eso, calcula el LCS de los dos arrays y emite inserciones y eliminaciones relativas a él. Para arrays de primitivos esto funciona bien. Para arrays de objetos no: [{id: 1, name: "Alice"}] versus [{id: 1, name: "Alicia"}] no tienen subsecuencia común por igualdad de referencia, así que el LCS ingenuo reporta «eliminar todo el elemento izquierdo, añadir todo el elemento derecho» cuando la verdad es que un campo de un elemento cambió. La solución de jsondiffpatch es el callback objectHash: el llamador proporciona una función que mapea cada objeto a una clave de identidad (típicamente obj => obj.id), y el diff hace coincidir los elementos del array por identidad en lugar de por referencia. Este es un problema general difícil que nadie ha resuelto del todo. La herramienta Absolutool, según su propia FAQ, compara arrays por índice, no implementa ni LCS ni objectHash. Esa es una elección de alcance deliberada para una pequeña herramienta gratuita: es excelente con diffs de objetos y más débil en arrays donde se han insertado o reordenado elementos.
JSON Patch (RFC 6902): los diffs como formato de transporte
RFC 6902, «JavaScript Object Notation (JSON) Patch», se publicó en abril de 2013. Define el tipo de medio application/json-patch+json y un lenguaje de patch de seis operaciones: add, remove, replace, move, copy, test. Un patch es en sí mismo un documento JSON, un array de objetos operación, cada uno con una clave op, una clave path (un JSON Pointer al lugar destino) y un campo valor o from según corresponda. Las operaciones se aplican en orden, atómicamente: si alguna falla, todo el patch se rechaza. La sintaxis del path viene de RFC 6901, «JSON Pointer», un documento compañero publicado el mismo mes, una sintaxis minúscula de cadena de tokens de referencia separados por barras (/user/address/city significa «el valor en la clave city dentro de address dentro de user»; /items/3 significa «el cuarto elemento de items», con índice cero). Como / y ~ son especiales, se escapan a ~1 y ~0 respectivamente (en ese orden, decodificar ~1 primero para evitar bugs de doble decodificación). JSON Patch es el formato de salida correcto para una herramienta de diff JSON que quiera alimentar el resultado a otra máquina. El método HTTP PATCH (RFC 5789) se diseñó exactamente para este tipo de carga útil de actualización parcial. Kubernetes soporta RFC 6902 junto a su propio formato strategic-merge-patch. Esta herramienta no emite actualmente JSON Patch, esa es una dirección de funcionalidad futura, no actual.
JSON Merge Patch (RFC 7396): la alternativa más simple, con pérdida
RFC 7396, «JSON Merge Patch», se publicó en octubre de 2014 por Paul Hoffman y James Snell. No usa operaciones en absoluto, el documento patch es simplemente un objeto JSON parcial que se superpone al original. Cualquier campo presente en el patch sobrescribe el campo correspondiente en el original; cualquier campo puesto a null en el patch elimina ese campo; cualquier campo ausente del patch queda sin cambios; los arrays se reemplazan al por mayor, nunca se fusionan. Merge Patch es conciso y fácil de escribir a mano. El compromiso es la pérdida de expresividad: no hay manera de poner el valor de un campo a null literal (porque null significa «eliminar»); no hay manera de modificar un solo elemento de un array (todo el array se reemplaza); no hay manera de expresar un move o copy; no hay manera de distinguir «no toqué este campo» de «quiero ponerlo a su valor actual». Para la mayoría de las actualizaciones diarias de API estas limitaciones son aceptables, por eso Merge Patch es el más popular de los dos formatos. RFC 6902 gana en escenarios donde alguna de las limitaciones muerde. Kubernetes usa ambos formatos deliberadamente, eligiendo el correcto para cada contexto.
Cómo se renderiza el diff visual
Hay tres convenciones visuales comunes para mostrar un diff estructural. Lado a lado, dos columnas, original a la izquierda, modificado a la derecha, con las líneas correspondientes alineadas (la disposición que esta herramienta usa para sus entradas). Diff unificado inline, una sola columna mostrando líneas eliminadas (típicamente prefijadas con - y coloreadas en rojo), líneas añadidas (+, verde) y líneas de contexto sin cambios (sin prefijo, texto plano), la disposición que git diff usa por defecto. Vista árbol, renderizar el JSON como un árbol colapsable, con los nodos cambiados resaltados y los nodos sin cambios plegados. Las convenciones de color son notablemente consistentes en el ecosistema: verde para adiciones, rojo para eliminaciones, amarillo o ámbar para valores cambiados, gris neutro para sin cambios. Esta herramienta sigue la convención exactamente: verde claro para adiciones, rojo claro para eliminaciones, amarillo claro para cambios. La mayoría de los usuarios reconocerán los colores desde GitHub, GitLab, BitBucket, cualquier vista de diff de IDE y docenas de herramientas en línea.
Usos habituales
- Comparar las respuestas de API antes y después de una modificación de código
- Encontrar las diferencias entre archivos de configuración
- Revisar lockfiles generados.
package-lock.json,yarn.lock,poetry.lock,Cargo.lockyterraform.tfstateson todos archivos JSON-o-JSON-adyacentes generados por máquina que cambian de formas ruidosas durante el desarrollo normal. Un diff JSON-aware es bastante más útil que un diff de texto para entender qué se movió realmente. - Verificar idas y vueltas de serialización. Serializar una fila de base de datos a JSON, pasarla por una red, deserializarla, reserializarla. ¿Cambió algo? Un diff atrapa bugs silenciosos en serializadores personalizados, especialmente alrededor de fechas, precisión numérica y manejo de null.
- Test de regresión de salidas JSON. Snapshotea una salida JSON buena conocida; diff cada ejecución posterior contra el snapshot y haz fallar el test si algo cambió.
- Comparar borradores de esquema. JSON Schema y los documentos OpenAPI son ellos mismos JSON. Differ dos versiones de un esquema revela exactamente qué campos se hicieron requeridos, opcionales o tuvieron sus tipos endurecidos.
- Verificar la exactitud de una migración de datos
Casos límite que vale la pena conocer
Precisión numérica. RFC 8259 dice que los números JSON son de precisión arbitraria y no pone límite superior a cuántos dígitos puede tener un número. JavaScript, sin embargo, parsea cada número como un double IEEE 754 de 64 bits. Por encima de Number.MAX_SAFE_INTEGER (253 − 1 = 9 007 199 254 740 991), los enteros pueden perder silenciosamente precisión al ir y volver a través de un diff basado en JavaScript. El mismo problema afecta a la coma flotante, 0.1 + 0.2 no es famosamente exactamente 0.3 en IEEE 754. El JSON estricto también prohíbe comas finales y comentarios; ambos son errores de sintaxis según RFC 8259. JSON5 (json5.org) es un sub-conjunto formal que permite comentarios, comas finales, comillas simples, claves sin comillas, números hex, puntos decimales iniciales/finales e Infinity/NaN. JSONC es el modo «JSON with Comments» de Microsoft usado en los archivos de configuración de VS Code. Esta herramienta usa JSON.parse() y por tanto rechazará ambos, quita comentarios y comas finales antes de pegar.
Cadenas de fecha. JSON no tiene tipo fecha nativo. Las fechas se codifican típicamente como cadenas, siendo el estándar de facto ISO 8601 (y específicamente el perfil RFC 3339 que la mayoría de las API de internet usan): YYYY-MM-DDTHH:MM:SS[.fff]Z. Un diff que compara fechas como cadenas reportará 2024-01-01T00:00:00Z y 2024-01-01T00:00:00.000Z como diferentes, aunque representen el mismo instante, porque las cadenas difieren. Claves duplicadas. RFC 8259 §4 dice «los nombres dentro de un objeto DEBERÍAN ser únicos», el DEBERÍAN es normativamente más débil que DEBEN. El JSON.parse() de JavaScript acepta claves duplicadas y silenciosamente se queda con la última; otros parsers pueden quedarse con la primera o levantar un error. null vs ausente. {"a": null} y {} son valores JSON diferentes. Esta herramienta reporta el primero como «la clave a tiene valor null» y el segundo como «no hay clave a», se distinguen correctamente. El trato de null por JSON Merge Patch como señal de eliminación es una admisión a nivel de formato de que la distinción es real y delicada.
El ecosistema en 2026
El diff JSON open-source está dominado por un puñado de bibliotecas. jsondiffpatch de Benjamin Eidelman, publicada por primera vez en 2012, es la biblioteca JavaScript de facto: ~5k estrellas en GitHub, soporta objectHash, arrays LCS, patches inversos y un formateador HTML visual. json-diff de Andrey Tarantsov es la herramienta CLI Node canónica, con el mismo nombre compartido por implementaciones paralelas en Python, Go y Rust. DeepDiff de Sep Dehpour es la biblioteca Python dominante, diff recursivo con opciones para ignorar orden, ignorar cambios de tipo numérico y un buen número de controles finos. El diff JsonNode de Jackson (Java) en la Linux Foundation es la elección estándar JVM. jq no tiene comando diff nativo pero su familia de operadores = y // puede expresar comparaciones estructurales simples. El diff integrado de VS Code maneja JSON vía modo texto; la extensión JSON Tools añade comparación JSON-aware. Herramientas en línea como Diffchecker ofrecen modos JSON que son esencialmente el mismo paseo recursivo que esta herramienta implementa, a menudo en capas sobre las mismas bibliotecas.
Por qué importa el solo-navegador aquí
Diffear dos payloads JSON en un servidor requiere subir ambos. Para ejemplos ordinarios de datos públicos es inofensivo. Para respuestas de API que contienen tokens de autenticación, PII de clientes, registros internos de empleados, secretos de configuración o datos de producto sin publicar, no lo es. Incluso después de que el diff termine, esos payloads quedan en logs del servidor, posiblemente en un caché CDN, posiblemente en una canalización de analítica, posiblemente en un backup. Un diff solo-navegador nunca transmite, el JSON se parsea y recorre enteramente en tu pestaña. Puedes verificarlo abriendo la pestaña Network de DevTools al pulsar Compare; no hay peticiones salientes. Para comparar respuestas de API contra una línea base, depurar deriva de configuración entre entornos o auditar cambios en un lockfile que contenga URLs de paquetes internos, «el JSON no abandona mi dispositivo» es la arquitectura que hace la herramienta segura de usar sobre datos de producción reales.
Preguntas frecuentes
¿El orden de las claves afecta a la comparación?
No. Los objetos JSON no están ordenados según la especificación, así que {"a":1, "b":2} y {"b":2, "a":1} se tratan como idénticos. Solo se señalan las diferencias reales de valor.
¿Cómo se comparan los arrays?
Los arrays se comparan por índice. Si el array en el índice 2 difiere entre las dos entradas, se señala ese índice específico. También se detectan los elementos añadidos o eliminados al final del array.
¿Qué ocurre con objetos profundamente anidados?
La comparación es totalmente recursiva. Los objetos y arrays anidados a cualquier profundidad se comparan propiedad por propiedad. La salida muestra la ruta completa de cada diferencia (p. ej. «user.address.city»).
¿Por qué mi comparación de enteros grandes parece mal?
JavaScript parsea cada número JSON como un double IEEE 754 de 64 bits. Por encima de Number.MAX_SAFE_INTEGER (253 − 1 = 9 007 199 254 740 991), los enteros pueden perder silenciosamente precisión. Así que un archivo JSON conteniendo 9007199254740993 puede comparar como idéntico a uno conteniendo 9007199254740992. Esta es una limitación de la representación numérica subyacente, no de la herramienta de diff. Si estás diffeando datos que contienen IDs de 64 bits (IDs snowflake de Twitter, IDs de Discord, claves grandes de base de datos), haz que tu serializador los emita como cadenas en vez de como números. La comparación de coma flotante tiene la misma advertencia: 0.1 + 0.2 no es famosamente exactamente 0.3 en IEEE 754.
¿Puedo comparar JSON5 o JSONC (JSON con comentarios)?
No directamente. Esta herramienta usa el JSON.parse() integrado del navegador, que sigue estrictamente RFC 8259, comentarios, comas finales, cadenas con comillas simples y claves sin comillas son errores de sintaxis. Si tu entrada es JSON5 (json5.org) o JSONC estilo VS Code, quita primero los comentarios y comas finales, o pásalo por una herramienta como jsonc-parser para convertir a JSON estricto antes de pegar.
¿Mi JSON se envía a un servidor?
No. La comparación se ejecuta enteramente en tu navegador vía JavaScript. El JSON pegado nunca cruza la red, verifícalo en la pestaña Network de DevTools al pulsar Compare, o pon la página offline tras cargar y confirma que el diff sigue funcionando. Segura para comparar respuestas de API con tokens de autenticación, archivos de configuración con secretos o exports de base de datos que contienen PII de clientes.