JavaScript에서 JSONL: 읽기, 쓰기 & 파싱

JavaScript에서 JSONL(JSON Lines) 파일을 다루기 위한 완전 가이드입니다. Node.js와 브라우저에서 내장 API와 인기 라이브러리를 사용하여 JSONL 데이터를 읽고, 쓰고, 파싱하고, 스트리밍하는 방법을 배우세요.

최종 업데이트: 2026년 2월

왜 JavaScript로 JSONL을?

JavaScript는 JSONL 파일을 다루는 데 자연스러운 언어입니다. JSON 자체가 JavaScript에서 탄생했기 때문에, 내장 JSON.parse() 및 JSON.stringify() 메서드를 통한 일급 파싱 지원이 제공됩니다. Node.js 데이터 파이프라인을 구축하든, 서버에서 로그 파일을 처리하든, 브라우저에서 사용자가 JSONL을 업로드하도록 하든, JavaScript는 모든 단계를 처리할 수 있는 도구를 제공합니다.

JSONL(JSON Lines)은 줄당 하나의 JSON 객체를 저장하므로 스트리밍, 추가 전용 로깅, 대용량 데이터셋의 줄 단위 처리에 이상적입니다. Node.js 스트림은 이 형식과 완벽하게 일치하여, 메모리 부족 없이 수백만 개의 레코드를 읽고 변환할 수 있습니다. 클라이언트 측에서는 브라우저 FileReader 및 Streams API를 사용하여 사용자 기기에서 완전히 JSONL 처리가 가능합니다. 이 가이드에서는 Node.js와 브라우저 모두에서 JSONL을 읽는 방법, JSONL 파일을 쓰는 방법, 스트리밍 변환 파이프라인을 구축하는 방법, 그리고 프로젝트에 적합한 npm 라이브러리를 선택하는 방법을 배우게 됩니다.

Node.js에서 JSONL 읽기

Node.js는 파일을 줄 단위로 효율적으로 읽기 위한 readline 모듈을 제공합니다. fs.createReadStream과 결합하면, 전체 파일을 메모리에 로드하는 대신 데이터를 스트리밍하기 때문에 서버에서 JSONL 파일을 처리하는 권장 방법입니다.

fs.createReadStream을 readline.createInterface에 파이프하여 JSONL 파일을 한 줄씩 읽습니다. 이 방식은 파일 크기에 관계없이 최소한의 메모리를 사용합니다.

readline을 사용한 스트림 읽기
import { createReadStream } from 'node:fs';
import { createInterface } from 'node:readline';
async function readJsonl(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;
}
// Usage
const data = await readJsonl('data.jsonl');
console.log(`Loaded ${data.length} records`);
console.log(data[0]);

메모리에 무리 없이 들어가는 소규모 JSONL 파일의 경우, 전체 파일을 한 번에 읽고 줄바꿈으로 분할할 수 있습니다. 스트리밍 효율성을 희생하고 간결함을 택하는 방법입니다.

간단한 원라이너 (소규모 파일)
import { readFileSync } from 'node:fs';
const records = readFileSync('data.jsonl', 'utf-8')
.split('\n')
.filter(line => line.trim())
.map(line => JSON.parse(line));
console.log(`Loaded ${records.length} records`);

브라우저에서 JSONL 읽기

브라우저에서 사용자는 파일 입력을 통해 JSONL 파일을 업로드할 수 있습니다. FileReader API 또는 최신 Streams API를 사용하여 서버로 데이터를 전송하지 않고 파일을 읽을 수 있습니다.

FileReader를 사용하여 사용자가 선택한 파일을 읽은 다음, 텍스트 콘텐츠를 줄로 분할하고 각각을 파싱합니다. 프라이버시를 위해 모든 데이터가 클라이언트 측에 유지됩니다.

브라우저 FileReader API
function parseJsonlFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
const text = reader.result;
const records = text
.split('\n')
.filter(line => line.trim())
.map(line => JSON.parse(line));
resolve(records);
};
reader.onerror = () => reject(reader.error);
reader.readAsText(file, 'utf-8');
});
}
// Usage with an <input type="file"> element
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
const file = e.target.files[0];
const records = await parseJsonlFile(file);
console.log(`Parsed ${records.length} records`);
});

브라우저에서 대용량 파일을 처리할 때는 TextDecoderStream과 함께 Streams API를 사용하여 파일을 청크 단위로 처리합니다. 전체 파일을 한 번에 메모리에 로드하지 않아도 됩니다.

브라우저 Streams API (대용량 파일)
async function* streamJsonl(file) {
const stream = file.stream()
.pipeThrough(new TextDecoderStream());
const reader = stream.getReader();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += value;
const lines = buffer.split('\n');
buffer = lines.pop(); // Keep incomplete last line
for (const line of lines) {
const trimmed = line.trim();
if (trimmed) yield JSON.parse(trimmed);
}
}
// Handle remaining buffer
if (buffer.trim()) {
yield JSON.parse(buffer.trim());
}
}
// Usage
for await (const record of streamJsonl(file)) {
console.log(record);
}

Node.js에서 JSONL 쓰기

Node.js에서 JSONL 파일을 쓰는 것은 간단합니다: 각 JavaScript 객체를 JSON 문자열로 직렬화하고 줄바꿈 문자를 추가하면 됩니다. 대용량 데이터셋에서 최상의 성능을 위해서는 전체 문자열을 메모리에 구축하는 대신 쓰기 스트림을 사용하세요.

fs.writeFileSync 또는 fs.createWriteStream을 사용하여 레코드를 JSONL 파일에 씁니다. 각 레코드는 줄바꿈이 뒤따르는 한 줄의 유효한 JSON입니다.

fs를 사용한 기본 쓰기
import { writeFileSync } from 'node:fs';
const records = [
{ id: 1, name: 'Alice', role: 'engineer' },
{ id: 2, name: 'Bob', role: 'designer' },
{ id: 3, name: 'Charlie', role: 'manager' },
];
const jsonl = records
.map(record => JSON.stringify(record))
.join('\n') + '\n';
writeFileSync('output.jsonl', jsonl, 'utf-8');
console.log(`Wrote ${records.length} records`);

수백만 개의 레코드를 쓸 때는 전체 출력 문자열을 메모리에 구축하지 않도록 쓰기 가능한 스트림을 사용합니다. 스트림은 OS 버퍼가 가득 찼을 때 자동으로 배압(backpressure)을 처리하여 쓰기를 일시 중지합니다.

대용량 데이터를 위한 스트리밍 쓰기
import { createWriteStream } from 'node:fs';
async function writeJsonl(filePath, records) {
const stream = createWriteStream(filePath, 'utf-8');
for (const record of records) {
const line = JSON.stringify(record) + '\n';
// Respect backpressure
if (!stream.write(line)) {
await new Promise(resolve => stream.once('drain', resolve));
}
}
stream.end();
await new Promise(resolve => stream.on('finish', resolve));
console.log('Write complete');
}
// Usage
const data = Array.from({ length: 100000 }, (_, i) => ({
id: i + 1,
value: Math.random(),
timestamp: new Date().toISOString(),
}));
await writeJsonl('large_output.jsonl', data);

JSONL 파이프라인을 위한 Transform 스트림

Node.js Transform 스트림을 사용하면 JSONL을 읽고, 각 레코드를 처리하고, 결과를 쓰는 조합 가능한 데이터 파이프라인을 구축할 수 있습니다. 이 패턴은 ETL 작업, 로그 처리, 데이터 마이그레이션에 이상적입니다.

JSONL 파이프라인을 위한 Transform 스트림
import { createReadStream, createWriteStream } from 'node:fs';
import { createInterface } from 'node:readline';
import { Transform } from 'node:stream';
import { pipeline } from 'node:stream/promises';
// Transform: parse JSONL line into object, process, stringify back
const transformJsonl = new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
const line = chunk.toString().trim();
if (!line) return callback();
try {
const record = JSON.parse(line);
// Add your transformation here
record.processed = true;
record.processedAt = new Date().toISOString();
callback(null, JSON.stringify(record) + '\n');
} catch (err) {
callback(err);
}
},
});
// Build the pipeline
const rl = createInterface({
input: createReadStream('input.jsonl', 'utf-8'),
crlfDelay: Infinity,
});
const output = createWriteStream('output.jsonl', 'utf-8');
for await (const line of rl) {
transformJsonl.write(line);
}
transformJsonl.end();
await pipeline(transformJsonl, output);
console.log('Pipeline complete');

이 파이프라인은 JSONL 파일을 줄 단위로 읽고, 각 레코드에 변환(processed 및 processedAt 필드 추가)을 적용한 다음 결과를 새 파일에 씁니다. Transform 스트림이 배압을 자동으로 처리하므로, 매우 큰 파일에서도 메모리 사용량이 일정하게 유지됩니다. 복잡한 ETL 워크플로우를 위해 여러 변환을 체인으로 연결할 수 있습니다.

JSONL용 JavaScript 라이브러리

내장 JSON.parse가 대부분의 경우를 잘 처리하지만, 스트리밍, 유효성 검사, 배치 처리와 같은 JSONL 전용 워크플로우를 위한 편리한 유틸리티를 제공하는 npm 패키지들이 있습니다.

JSON.parse (내장)

내장

내장 JSON.parse()와 JSON.stringify()는 V8에서 고도로 최적화되어 있으며 대부분의 JSONL 사용 사례에 충분합니다. 스트리밍을 위해 readline과 결합하세요. 의존성이 필요 없으며, 수백 MB 규모의 파일까지 성능이 우수합니다.

ndjson

인기

ndjson은 Node.js 스트림과 호환되는 스트리밍 JSONL(Newline Delimited JSON) 파서 및 직렬화기를 제공하는 인기 npm 패키지입니다. 파싱 오류를 우아하게 처리하며 기존 스트림 파이프라인과 잘 통합됩니다. 빠른 프로토타이핑에 적합합니다.

jsonl-parse-stringify

심플

jsonl-parse-stringify는 JSONL 데이터를 위한 간단한 parse() 및 stringify() 메서드를 제공하는 경량 무의존성 라이브러리입니다. 후행 줄바꿈 및 빈 줄과 같은 엣지 케이스를 처리합니다. 스트림 설정 없이 깔끔한 동기 API가 필요할 때 이상적입니다.

무료 JSONL 도구를 사용해 보세요

코드를 작성하고 싶지 않으신가요? 무료 온라인 도구를 사용하여 브라우저에서 바로 JSONL 파일을 보고, 변환하고, 포맷하세요. 모든 처리는 로컬에서 이루어지므로 데이터는 안전합니다.

온라인에서 JSONL 파일 작업하기

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

자주 묻는 질문

JavaScript에서 JSONL — Node에서 JSON Lines 읽기, 쓰기 & 스트리밍 | js...