NDJSON 완전 가이드: Newline Delimited JSON 설명

Newline Delimited JSON(NDJSON)에 대한 종합 가이드입니다. 사양, MIME 타입, Python, Node.js, 커맨드라인에서 NDJSON을 읽고 쓰는 방법, 스트리밍 HTTP API에서의 사용, JSONL과의 관계를 배우세요.

최종 업데이트: 2026년 2월

NDJSON이란?

NDJSON은 Newline Delimited JSON의 약자입니다. 각 줄에 정확히 하나의 유효한 JSON 값이 포함되며 줄바꿈 문자(\n)로 구분되는 텍스트 기반 데이터 형식입니다. 이 형식은 전체 파일을 메모리에 로드하지 않고 대규모 데이터셋을 스트리밍하고 처리하기 위해 설계되었습니다. 모든 것을 단일 배열이나 객체로 감싸는 표준 JSON 파일과 달리, NDJSON은 레코드를 하나씩 읽고 쓰고 처리할 수 있게 합니다.

NDJSON 사양은 github.com/ndjson/ndjson-spec에서 호스팅됩니다. 로그 전송, 데이터 파이프라인, HTTP 스트리밍 API에서 이미 보편화된 패턴을 공식화하기 위해 만들어졌습니다. 각 줄은 자체 완결적입니다: 한 줄에 유효하지 않은 JSON이 포함되더라도 다른 줄은 여전히 성공적으로 파싱할 수 있습니다. 이로 인해 NDJSON은 애플리케이션 로그, 이벤트 스트림, 점진적 데이터 내보내기와 같은 추가 전용 워크플로우에 내결함성이 있고 적합합니다.

NDJSON 예제 (3개 레코드)
{"id":1,"event":"page_view","url":"/home"}
{"id":2,"event":"click","url":"/pricing"}
{"id":3,"event":"signup","url":"/register"}

NDJSON 사양

github.com/ndjson/ndjson-spec의 공식 NDJSON 사양은 의도적으로 최소한입니다. 단일 텍스트 스트림에서 여러 JSON 값을 직렬화하기 위한 간단한 규칙을 정의합니다. 핵심 규칙은 간단합니다:

이 사양은 형식에 헤더, 메타데이터, 스키마 정보를 추가하는 것을 명시적으로 피합니다. 이를 통해 NDJSON을 최대한 간단하게 유지하고 표준 Unix 텍스트 처리 도구와 호환됩니다. 각 줄에 모든 유효한 JSON 값이 허용되지만, 실제로 대부분의 NDJSON 파일은 일관된 키 집합을 가진 JSON 객체를 포함합니다.

  • 각 줄은 정확히 하나의 유효한 JSON 값(객체, 배열, 문자열, 숫자, 불리언 또는 null)을 포함해야 합니다.
  • 줄은 줄바꿈 문자 '\n'(U+000A)으로 구분됩니다. 캐리지 리턴 '\r'(U+000D)은 '\n' 앞에 올 수 있지만 필수는 아닙니다.
  • 마지막 JSON 값 뒤의 후행 줄바꿈은 허용되지만 필수는 아닙니다.
  • 각 JSON 값에는 값 자체 내에 이스케이프되지 않은 줄바꿈 문자가 포함되어서는 안 됩니다.

규칙이 최소한이므로 JSON 직렬라이저가 있는 모든 프로그래밍 언어에서 NDJSON을 쉽게 생성할 수 있습니다. 각 레코드를 직렬화하고, 줄바꿈을 추가하고, 출력에 쓰기만 하면 됩니다. 닫는 괄호, 후행 쉼표, 감싸는 배열 구조에 대해 걱정할 필요가 없습니다.

NDJSON vs JSON vs JSONL

NDJSON, JSON, JSONL은 각각 다른 구조를 가지고 있습니다. 표준 JSON은 단일 값(보통 배열이나 객체)을 인코딩합니다. JSONL과 NDJSON은 모두 줄당 하나의 JSON 값을 저장하며 기능적으로 동일합니다. 아래 표는 세 형식 간의 주요 차이점을 강조합니다.

기능JSONJSONLNDJSON
전체 이름JavaScript Object NotationJSON LinesNewline Delimited JSON
파일 확장자.json.jsonl.ndjson
MIME 타입application/jsonapplication/jsonl (비공식)application/x-ndjson
사양RFC 8259 (IETF 표준)jsonlines.org (커뮤니티)github.com/ndjson/ndjson-spec (커뮤니티)
줄 구분자해당 없음 (단일 값)\n (줄바꿈)\n (줄바꿈)
후행 줄바꿈해당 없음권장선택 사항
스트리밍 친화적아니오 (전체 문서를 파싱해야 함)예 (줄 단위)예 (줄 단위)

NDJSON MIME 타입: application/x-ndjson

NDJSON의 등록된 MIME 타입은 application/x-ndjson입니다. 이 콘텐츠 타입은 응답 본문에 줄바꿈 구분 JSON 데이터가 포함되어 있음을 나타내기 위해 HTTP 헤더에서 사용됩니다. GitHub API, Docker Registry API, Elasticsearch bulk API를 포함한 많은 스트리밍 API가 NDJSON 응답을 전달하기 위해 이 MIME 타입을 사용합니다.

HTTP Content-Type 헤더
Content-Type: application/x-ndjson
# Example: curl a streaming API
curl -H "Accept: application/x-ndjson" https://api.example.com/events/stream
# Example: Express.js response
res.setHeader('Content-Type', 'application/x-ndjson');
res.write(JSON.stringify(record) + '\n');

일부 API는 application/json-seq(RFC 7464)이나 text/plain도 대안으로 수락합니다. 그러나 application/x-ndjson이 줄바꿈 구분 JSON 스트림에 가장 널리 채택된 MIME 타입입니다. JSON 레코드를 스트리밍하는 새 API를 구축할 때는 최대 호환성을 위해 application/x-ndjson을 사용하세요.

NDJSON 읽기 및 쓰기

JSON을 지원하는 모든 언어에서 NDJSON 작업은 간단합니다. 아래는 Python, Node.js, 커맨드라인에 대한 실용적인 예제입니다.

Python의 내장 json 모듈은 NDJSON을 자연스럽게 처리합니다. 파일에서 줄을 읽고 각각을 json.loads로 파싱하고 json.dumps로 씁니다. 대용량 파일의 경우 이 줄 단위 접근 방식은 일정한 메모리를 사용합니다.

Python: NDJSON 읽기 및 쓰기
guide-ndjson-complete-guide.ndjsonGuide.readWrite.python.code

Node.js에서는 readline 모듈과 fs.createReadStream을 사용하여 NDJSON 파일을 효율적으로 파싱합니다. 스트림은 한 번에 한 줄씩 처리하므로 파일 크기에 관계없이 메모리 사용량이 낮게 유지됩니다.

Node.js: NDJSON 읽기 및 쓰기
import { createReadStream, writeFileSync } from 'node:fs';
import { createInterface } from 'node:readline';
// Read NDJSON
async function readNdjson(filePath) {
const records = [];
const rl = createInterface({
input: createReadStream(filePath, 'utf-8'),
crlfDelay: Infinity,
});
for await (const line of rl) {
const trimmed = line.trim();
if (trimmed) records.push(JSON.parse(trimmed));
}
return records;
}
// Write NDJSON
const data = [
{ id: 1, event: 'page_view' },
{ id: 2, event: 'click' },
];
const ndjson = data.map(r => JSON.stringify(r)).join('\n') + '\n';
writeFileSync('output.ndjson', ndjson, 'utf-8');

jq 커맨드라인 도구는 NDJSON 입력을 네이티브로 이해합니다. --slurp 플래그를 사용하여 모든 레코드를 배열로 수집하거나, 플래그 없이 각 레코드를 개별적으로 처리합니다.

커맨드라인: jq로 NDJSON 처리
# Print each record (jq reads NDJSON by default)
jq '.' data.ndjson
# Filter records where event is "click"
jq 'select(.event == "click")' data.ndjson
# Extract specific fields
jq {id, url} data.ndjson
# Count total records
jq -s 'length' data.ndjson
# Convert NDJSON to a JSON array
jq -s '.' data.ndjson > data.json
# Convert a JSON array back to NDJSON
jq -c '.[]' data.json > data.ndjson

HTTP 스트리밍 API에서의 NDJSON

NDJSON은 실시간 데이터를 전달하는 HTTP 스트리밍 API의 사실상 표준입니다. 서버가 NDJSON 응답을 보내면 클라이언트는 전체 응답이 완료될 때까지 기다리지 않고 첫 번째 레코드가 도착하는 즉시 처리를 시작할 수 있습니다. 이는 대형 JSON 배열을 반환하는 것보다 빠르고 메모리 효율적입니다.

NDJSON 스트리밍을 사용하는 인기 서비스로는 Docker Registry(이미지 레이어 이벤트), Elasticsearch(대량 작업), Apache CouchDB(변경 피드) 및 많은 최신 이벤트 기반 API가 있습니다. 이 패턴은 Server-Sent Events 대안, 실시간 로그 테일링, 웹 애플리케이션의 점진적 데이터 로딩과 잘 작동합니다.

Express.js NDJSON 스트리밍 서버
import express from 'express';
const app = express();
app.get('/api/events/stream', (req, res) => {
res.setHeader('Content-Type', 'application/x-ndjson');
res.setHeader('Transfer-Encoding', 'chunked');
// Simulate streaming events
let id = 0;
const interval = setInterval(() => {
id++;
const event = {
id,
type: 'heartbeat',
timestamp: new Date().toISOString(),
};
res.write(JSON.stringify(event) + '\n');
if (id >= 100) {
clearInterval(interval);
res.end();
}
}, 100);
req.on('close', () => clearInterval(interval));
});
app.listen(3000);
브라우저: Fetch로 NDJSON 스트림 소비
async function* readNdjsonStream(url) {
const response = await fetch(url, {
headers: { 'Accept': 'application/x-ndjson' },
});
const reader = response.body
.pipeThrough(new TextDecoderStream())
.getReader();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += value;
const lines = buffer.split('\n');
buffer = lines.pop();
for (const line of lines) {
if (line.trim()) yield JSON.parse(line);
}
}
if (buffer.trim()) yield JSON.parse(buffer);
}
// Usage
for await (const event of readNdjsonStream('/api/events/stream')) {
console.log('Received:', event);
}

NDJSON 에코시스템 도구

점점 늘어나는 커맨드라인 도구와 라이브러리 에코시스템이 NDJSON을 네이티브로 지원합니다. 이러한 도구를 사용하면 커스텀 코드를 작성하지 않고 NDJSON 데이터를 필터링, 변환, 분석할 수 있습니다.

jq

필수

jq는 가장 인기 있는 커맨드라인 JSON 프로세서입니다. 기본적으로 NDJSON을 읽고(줄당 하나의 JSON 값) 필터링, 매핑, 그룹화, 재포맷을 지원합니다. 컴팩트 출력에는 jq -c를, 모든 레코드를 배열로 모으려면 jq -s를 사용하세요.

ndjson-cli

CLI

ndjson-cli는 NDJSON 스트림을 조작하기 위한 Unix 스타일 명령 모음입니다: ndjson-filter, ndjson-map, ndjson-reduce, ndjson-sort, ndjson-join. 각 명령은 stdin에서 읽고 stdout에 쓰므로 파이프로 조합할 수 있습니다.

ndjson (npm)

Node.js

ndjson npm 패키지는 Node.js용 스트리밍 NDJSON 파서와 직렬라이저를 제공합니다. 고처리량 데이터 처리를 위해 Node.js 스트림 파이프라인에 직접 통합되는 ndjson.parse()와 ndjson.stringify() Transform 스트림을 노출합니다.

NDJSON과 JSONL: 상호 운용성

NDJSON과 JSONL(JSON Lines)은 기능적으로 동일한 형식입니다. 둘 다 줄바꿈 문자로 구분된 줄당 하나의 JSON 값을 저장합니다. 유효한 NDJSON 파일은 유효한 JSONL이기도 하며, 그 반대도 마찬가지입니다. .ndjson 파일을 .jsonl로 이름을 바꿔도(또는 그 반대로) 단 한 바이트의 내용도 변경하지 않아도 되며, 한 형식을 읽는 모든 도구가 다른 형식도 읽을 수 있습니다.

유일한 차이점은 외관적입니다: NDJSON은 github.com/ndjson/ndjson-spec에서 온 것으로 .ndjson 확장자와 application/x-ndjson MIME 타입을 사용하고, JSONL은 jsonlines.org에서 온 것으로 .jsonl 확장자를 사용합니다. 실제로 대부분의 개발자는 두 이름을 동의어로 취급합니다. 프로젝트에서 이미 JSONL을 사용하고 있다면 NDJSON으로 마이그레이션할 필요가 없으며, 라이브러리가 NDJSON을 지원한다고 하면 .jsonl 파일에서도 변경 없이 작동합니다.

JSONL vs NDJSON: 상세 비교

JSONL과 NDJSON의 역사, 사양 차이, 커뮤니티 채택에 대한 더 깊은 분석은 전용 비교 가이드를 읽어보세요.

무료 NDJSON/JSONL 도구 사용해보기

브라우저에서 바로 NDJSON과 JSONL 파일을 작업하세요. 모든 처리는 로컬에서 이루어지므로 데이터 프라이버시가 보장됩니다.

온라인으로 NDJSON 파일 작업하기

브라우저에서 최대 1GB의 NDJSON 및 JSONL 파일을 보고, 검증하고, 변환하세요. 업로드 불필요, 100% 프라이빗.

자주 묻는 질문

NDJSON 형식 가이드 — Newline Delimited JSON & JSONL 설명 | jsonl.co