NDJSON

O que é um arquivo NDJSON?

Um objeto JSON por linha. É o que esteiras de log e exportações de dados emitem.

O que é NDJSON

NDJSON é um formato de texto puro que abre em qualquer editor. Ele é usado para mover dados entre programas e a transmissão.

A extensão é .ndjson e o nome por extenso é Newline-Delimited JSON. Os dois importam menos do que aquilo que o arquivo consegue carregar, e é disso que trata o resto desta página.

De onde vem NDJSON

Ele remonta a 2013.

A idade interessa por um motivo prático: quanto mais antigo o formato, mais programas tiveram tempo de aprendê-lo.

A especificação é pública

Ela está publicada por inteiro, então dá para implementá-la a partir do documento em vez de por observação — é por isso que o formato aparece em tantos programas e por isso que arquivos escritos há vinte anos ainda abrem. Especificação publicada não é o mesmo que livre de royalties: quando o formato embrulha um codec, o licenciamento das patentes é uma questão à parte, que a norma não resolve.

Nada é jogado fora

NDJSON guarda o conteúdo exatamente. Salvar de novo não muda nada, então dá para abrir, editar e salvar quantas vezes você quiser sem acumular estrago — e é isso que faz dele um formato de trabalho e não de entrega.

O que mais ele carrega

NDJSON consegue carregar um arranjo que permite começar a tocar antes de ter chegado por inteiro.

Isso conta sobretudo na conversão: o que o destino não comporta é descartado, quase sempre sem aviso.

Não há onde deixar uma anotação

NDJSON não tem sintaxe de comentário. Tudo que explica precisa morar fora do arquivo, e é bom saber disso antes de escolhê-lo para algo que uma pessoa vai editar na mão.

O que abre NDJSON

jq e pandas leem esse formato, e a maioria dos programas do mesmo tipo também.

Quando um arquivo não abre, o formato raramente é o problema — mais comum é o programa ser mais antigo que ele. Converter para algo mais antigo é o caminho confiável, e é para isso que serve o resto deste site.

Abrir no navegador

Nenhum navegador lê o formato.

Esse é de longe o motivo mais comum para convertê-lo: não que o formato seja ruim, mas que o lugar onde você quer mostrar o arquivo não consegue lê-lo.

É um formato de trabalho

NDJSON foi feito para ser aberto e alterado. Mantenha o arquivo nesse formato enquanto o trabalho estiver em andamento e exporte a partir dele sempre que precisar de uma cópia pronta.

Um array JSON não pode ser lido antes de terminar

Este é o problema para o qual o formato existe. Um documento JSON só é válido quando o colchete de fechamento chega, então um interpretador recebendo um array de dez gigabytes precisa ler os dez gigabytes inteiros na memória antes de devolver o primeiro registro. Para um fluxo de log que nunca termina, ele nunca consegue devolver nada.

O NDJSON remove o array. Cada linha é um objeto JSON completo e independente, terminado por uma quebra de linha e cercado de nada. Um leitor pega uma linha, interpreta, processa e esquece — então o uso de memória é do tamanho do maior registro, não do arquivo inteiro, e um processo pode começar a trabalhar no primeiro registro imediatamente.

Anexar é a outra metade do argumento

Adicionar um registro a um array JSON significa reescrever o arquivo: o colchete de fechamento está no final, e algo precisa entrar antes dele. Adicionar um registro a um arquivo NDJSON significa escrever uma linha.

É isso que o torna o formato natural para qualquer coisa que se acumula com o tempo — logs de aplicação, fluxos de eventos, trilhas de auditoria, dados raspados, telemetria. Também é o que o torna seguro sob concorrência de um jeito que um array JSON não é: uma escrita única de uma linha dentro do tamanho de escrita atômica do sistema não vai se intercalar com a linha de outro escritor, então vários processos conseguem anexar ao mesmo arquivo sem corrompê-lo.

O dano fica contido a uma linha

Um array JSON truncado por uma queda ou um disco cheio é inválido por inteiro — um colchete faltando e um interpretador rejeita o arquivo todo, incluindo os 99 por cento que chegaram perfeitamente.

Um arquivo NDJSON truncado no meio da escrita perde só a última linha e nada mais. Toda linha completa antes disso continua interpretável, e um leitor pode pular a quebrada e continuar. Para dados coletados ao longo de semanas e guardados em hardware que eventualmente vai falhar, essa diferença não é acadêmica.

Onde você encontra isso

Envio de logs e observabilidade: a API bulk do Elasticsearch, Logstash, Fluentd, Vector e a maioria das bibliotecas de log estruturado falam esse formato. Exportações de dados de APIs que devolvem mais linhas do que cabe numa resposta. Conjuntos de dados de aprendizado de máquina, onde os dados de treino são um exemplo por linha e o arquivo é lido em loop de fluxo contínuo.

Também como formato de transmissão para requisições longas, onde um servidor escreve um objeto JSON por linha conforme os resultados ficam disponíveis e o cliente processa conforme chegam em vez de esperar a resposta inteira.

As regras que fazem funcionar

Um objeto por linha, e nenhuma quebra de linha dentro dele. Uma string JSON pode legalmente conter uma quebra de linha escapada e nunca deve conter uma literal — um objeto formatado com indentação espalhado por várias linhas quebra o formato completamente, e essa é de longe a forma mais comum de um arquivo NDJSON ser gerado errado.

UTF-8, sem marca de ordem de byte, e uma quebra de linha no final da última linha em vez de faltando ou uma linha em branco sobrando. Terminações de linha deveriam ser do tipo de um caractere só: um retorno de carro do Windows antes de cada quebra é tolerado pela maioria dos leitores e rejeitado por alguns.

NDJSON, JSON Lines e JSONL

Três nomes para a mesma coisa. NDJSON é a especificação com um tipo de mídia; JSON Lines é uma descrição escrita separadamente do formato idêntico; JSONL é a extensão que as pessoas usam, particularmente em aprendizado de máquina.

As diferenças entre as especificações são cosméticas — uma nota sobre terminação de linha aqui, uma extensão permitida ali — e nenhuma ferramenta na prática as distingue. Um arquivo com qualquer uma das extensões pode ser entregue a algo que espera a outra.

Convertendo de e para NDJSON

Para JSON, quando um consumidor quer um documento único: envolva as linhas em colchetes e junte com vírgulas. Trivial, e reintroduz o problema de memória, que geralmente é o motivo do arquivo ser NDJSON em primeiro lugar.

Para CSV, quando os dados são realmente registros planos e alguém quer uma planilha. O problema é que JSON aninha e CSV não, então objetos aninhados precisam ser achatados em nomes de coluna com ponto e arrays precisam ser descartados ou unidos — uma etapa com perda que serve para relatório e é errada para um arquivamento.

E para Parquet para qualquer coisa analítica. Um formato colunar, comprimido e tipado lê dramaticamente mais rápido para as consultas que as pessoas realmente fazem contra dados de evento, e é para onde um grande acervo NDJSON geralmente quer ir.

Os dados, num lugar só

Identificadores e procedência do formato NDJSON.
Extensão.ndjson, .jsonl
Tipo de mídiaapplication/x-ndjson
Primeira publicação2013

Arquivos NDJSON: perguntas frequentes

Qual a diferença entre NDJSON e JSON?

Um arquivo JSON é um documento único que precisa ser lido inteiro antes de qualquer coisa poder ser usada. Um arquivo NDJSON é um objeto JSON completo por linha, então transmite em fluxo — o uso de memória é do tamanho de um registro, não do arquivo inteiro, e o processamento pode começar na primeira linha.

NDJSON, JSONL e JSON Lines são a mesma coisa?

Sim. Três nomes e duas especificações quase idênticas para um formato. Nenhuma ferramenta na prática as distingue, e um arquivo com qualquer extensão pode ser dado a algo que espera a outra.

Como eu abro um arquivo NDJSON?

Qualquer editor de texto para um pequeno, já que é texto simples com um registro por linha. Para algo grande, use uma ferramenta que transmite em fluxo — um editor de código que lê em blocos, um paginador, ou utilitários de linha de comando feitos para dados orientados a linha.

Um registro pode ocupar várias linhas?

Não, e essa é a forma mais comum do formato ser gerado errado. Um objeto JSON formatado com indentação espalhado por várias linhas quebra completamente. Quebras de linha dentro de strings precisam ser escapadas; uma literal encerra o registro.

Por que NDJSON é melhor para logs?

Anexar um registro é escrever uma linha em vez de reescrever um arquivo, vários processos conseguem anexar com segurança, e um arquivo truncado por uma queda perde só a última linha. Um array JSON truncado é inválido por inteiro, incluindo a parte que chegou perfeitamente.

Como eu converto NDJSON para CSV?

Funciona quando os registros são planos. JSON aninha e CSV não, então objetos aninhados precisam ser achatados em nomes de coluna com ponto e arrays descartados ou unidos — aceitável para relatório, com perda para um arquivamento. Para análise, Parquet é o destino melhor.