NDJSON

¿Qué es un archivo NDJSON?

Un objeto JSON por línea. Lo que emiten las tuberías de registros y las exportaciones de datos.

Qué es NDJSON

NDJSON es un formato de texto plano que se abre en cualquier editor. Se usa para mover datos entre programas y la transmisión.

La extensión es .ndjson y el nombre completo, Newline-Delimited JSON. Ambos importan menos que lo que el archivo puede contener, y de eso trata el resto de esta página.

De dónde viene NDJSON

Se remonta a 2013.

La edad interesa por un motivo práctico: cuanto más antiguo es un formato, más programas han tenido tiempo de aprenderlo.

La especificación es pública

Está publicada entera, así que cualquiera puede implementarla leyendo el documento en vez de a base de inspeccionar archivos. Por eso aparece en tantos programas, y por eso los archivos escritos hace veinte años siguen abriéndose hoy. Publicada no quiere decir libre de regalías: cuando un formato envuelve un códec, la licencia de las patentes es un asunto aparte que la norma no resuelve.

No se tira nada

NDJSON guarda su contenido exactamente. Volver a guardarlo no cambia nada, así que puedes abrirlo, editarlo y guardarlo tantas veces como quieras sin acumular daño; eso es lo que lo convierte en un formato de trabajo y no de entrega.

Qué más puede llevar

NDJSON puede contener una disposición que le permite empezar a reproducirse antes de haber llegado entero.

Eso importa sobre todo al convertir: lo que el destino no puede contener se descarta, casi siempre sin aviso.

No hay dónde dejar una nota

NDJSON no tiene sintaxis de comentarios. Todo lo explicativo tiene que vivir fuera del archivo, y conviene saberlo antes de elegirlo para algo que una persona vaya a editar a mano.

Qué abre NDJSON

jq y pandas lo leen, y también la mayoría de programas del mismo tipo.

Cuando un archivo no se abre, el formato rara vez es el problema: lo más habitual es que el programa sea anterior al formato. Convertir a algo más antiguo es la salida fiable, y para eso está el resto de este sitio.

Abrirlo en el navegador

Ningún navegador lo lee.

Ese es el motivo más frecuente para convertirlo: no que el formato sea malo, sino que el sitio donde quieres mostrar el archivo no sabe leerlo.

Es un formato de trabajo

NDJSON está pensado para abrirse y cambiarse. Guarda el archivo en este formato mientras el trabajo siga en marcha y exporta desde él cada vez que haga falta una copia terminada.

Un array JSON no existe hasta que aparece el corchete final

Este es el problema que el formato viene a resolver. Un documento JSON solo es válido cuando llega su cierre, así que un analizador al que le entregas un array de diez gigas de registros tiene que leer los diez gigas enteros antes de poder devolver el primero. Y con un flujo de eventos que no termina nunca, no podrá devolver nada jamás.

NDJSON quita el array. Cada línea es un objeto JSON completo e independiente, terminado en un salto de línea y rodeado de nada. El lector coge una línea, la analiza, la procesa y la olvida: la memoria que gasta es del tamaño del registro más grande y no del archivo, y el trabajo empieza en el primer registro en lugar de en el último.

Añadir un registro es escribir una línea

Meter un elemento en un array JSON obliga a reescribir el archivo, porque el corchete de cierre está al final y algo tiene que colocarse antes. Meter un registro en un NDJSON es abrir en modo añadir y escribir una línea.

De ahí que sea el formato natural de todo lo que se acumula con el tiempo: registros de aplicación, flujos de eventos, pistas de auditoría, datos extraídos, telemetría. Y por eso aguanta la concurrencia de una manera que un array no: una escritura única por debajo del tamaño atómico del sistema no se entrelaza con la línea de otro proceso, así que varios escritores pueden añadir al mismo archivo sin corromperlo.

Un corte a mitad de escritura solo se lleva la última línea

Un array JSON truncado por una caída o por un disco lleno es inválido entero. Falta un corchete y el analizador rechaza el archivo completo, incluido el 99 % que había llegado perfectamente.

Un NDJSON cortado a mitad pierde la última línea y nada más. Todas las anteriores siguen analizándose, y el lector puede saltarse la rota y seguir. Para datos recogidos durante semanas sobre hardware que algún día fallará, esa diferencia no es un detalle académico.

Dónde te lo vas a encontrar

En observabilidad y envío de registros: la API masiva de Elasticsearch, Logstash, Fluentd, Vector y la mayoría de las bibliotecas de log estructurado lo hablan. En exportaciones de API que devuelven más filas de las que caben en una respuesta. Y en conjuntos de datos de aprendizaje automático, donde el entrenamiento es un ejemplo por línea y el archivo se lee en bucle.

También como formato de transporte en peticiones largas, donde el servidor escribe un objeto JSON por línea a medida que hay resultados y el cliente los va procesando en lugar de esperar a que la respuesta termine.

Las dos reglas que lo mantienen en pie

Un objeto por línea y ningún salto de línea dentro. Una cadena JSON puede llevar un salto escapado y no puede llevar uno literal: un objeto formateado con sangría y repartido en varias líneas rompe el formato por completo, y esta es con diferencia la forma más común de generar mal un NDJSON.

Y la parte aburrida: UTF-8, sin marca de orden de bytes, con salto de línea al final de la última línea y sin línea en blanco de más. El final de línea debería ser el de un solo carácter; el retorno de carro de Windows delante de cada salto lo toleran casi todos los lectores y lo rechazan algunos, que es exactamente el tipo de fallo intermitente que nadie disfruta diagnosticando.

NDJSON, JSON Lines y JSONL son lo mismo

Tres nombres para una sola cosa. NDJSON es la especificación con tipo de medio propio; JSON Lines es una descripción escrita aparte del formato idéntico; JSONL es la extensión que usa la gente, sobre todo en aprendizaje automático.

Las diferencias entre los textos son cosméticas — una nota sobre finales de línea aquí, una extensión permitida allá — y en la práctica ninguna herramienta las distingue. Un archivo con cualquiera de las extensiones se le puede entregar a algo que espera la otra.

Qué se conserva y qué se aplana al convertirlo

Hacia JSON, YAML, TOML, XML o de vuelta a NDJSON, el árbol se mantiene: los objetos anidados siguen anidados y el orden de las claves se respeta, porque en ningún punto del camino hay una ordenación. Es la conversión sin sorpresas.

Hacia CSV, TSV, XLSX, Parquet, SQL o INI ocurre lo contrario, y hay que saberlo antes: la estructura se aplana en una columna por hoja del árbol, con la ruta separada por puntos como nombre de columna y los índices de los arrays como un tramo más de esa ruta. Para un informe está bien; para un archivo histórico no, porque el nombre de columna describe el árbol pero no lo reconstruye.

Los tres destinos habituales y lo que cuesta cada uno

A JSON, cuando quien consume quiere un único documento: envolver las líneas y unirlas con comas. Es trivial y reintroduce el problema de memoria, que suele ser la razón por la que el archivo era NDJSON.

A CSV o a XLSX, cuando los registros son realmente planos y alguien quiere abrirlos en una hoja de cálculo. Ten en cuenta que la escritura de XLSX produce una sola hoja, sin fórmulas, sin formatos y sin anchos de columna, con el nombre tomado del archivo de origen y recortado a 31 caracteres.

Y a Parquet para cualquier trabajo analítico. Ahí los tipos no se transportan, se vuelven a deducir columna a columna, y solo se escriben cuatro tipos físicos: booleano, entero de 32 bits, doble y texto. Un valor no numérico en una columna la convierte entera en texto, y los enteros que no caben en 32 bits pasan a doble. Si lo que quieres es cargar filas en una base de datos, la salida SQL contiene solo sentencias INSERT: no hay CREATE TABLE ni tipos, y la tabla se llama como el archivo.

Los datos, en un solo sitio

Identificadores y procedencia del formato NDJSON.
Extensión.ndjson, .jsonl
Tipo de medioapplication/x-ndjson
Primera publicación2013

NDJSON: preguntas que aparecen siempre

¿Qué diferencia hay entre NDJSON y JSON?

Un archivo JSON es un documento que hay que leer entero antes de poder usar nada. Un NDJSON es un objeto JSON completo por línea, así que se procesa en flujo: la memoria que gasta es la de un registro y el trabajo empieza en la primera línea.

¿NDJSON, JSONL y JSON Lines son lo mismo?

Sí. Tres nombres y dos especificaciones casi idénticas para un solo formato. Ninguna herramienta los distingue en la práctica, y un archivo con cualquiera de las extensiones sirve donde se espera la otra.

¿Con qué abro un archivo NDJSON?

Si es pequeño, con cualquier editor de texto, porque es texto plano con un registro por línea. Si es grande, con algo que lea en flujo: un editor de código que cargue por trozos, un paginador o utilidades de línea de órdenes pensadas para datos por líneas.

¿Un registro puede ocupar varias líneas?

No, y es la forma más común de generar mal el formato. Un objeto JSON formateado con sangría y repartido en varias líneas lo rompe entero. Los saltos dentro de una cadena tienen que ir escapados: uno literal termina el registro.

¿Por qué es mejor para registros de aplicación?

Porque añadir es escribir una línea en lugar de reescribir un archivo, varios procesos pueden añadir a la vez sin corromperlo, y un corte a mitad de escritura solo se lleva la última línea. Un array JSON truncado es inválido entero.

¿Qué pierdo al pasarlo a CSV?

La estructura. JSON anida y CSV no, así que los objetos anidados se aplanan en columnas con nombres separados por puntos y los índices de array pasan a formar parte de ese nombre. Vale para informes y no vale como archivo histórico; para análisis, Parquet es mejor destino.