JSONL vs NDJSON: 違いは何か?
JSONL(JSON Lines)と NDJSON(Newline Delimited JSON)を比較する完全ガイド — ほぼ同じフォーマットの 2 つの名称ですが、知っておく価値のある微妙な違いがあります。
最終更新: 2026年2月
JSONL vs NDJSON: クイック比較
| 特徴 | JSONL(JSON Lines) | NDJSON |
|---|---|---|
| 正式名称 | JSON Lines | Newline Delimited JSON |
| ファイル拡張子 | .jsonl | .ndjson |
| 仕様 | jsonlines.org(非公式) | github.com/ndjson/ndjson-spec(非公式仕様) |
| 起源 | コミュニティの慣習、データサイエンスツールで普及 | Chris Olah、Thorsten Ball らによって提案 |
| 行区切り文字 | \n(改行) | \n(改行) |
| MIME タイプ | application/jsonl(非公式) | application/x-ndjson |
| ストリーミング対応 | 対応、行単位 | 対応、行単位 |
| 採用状況 | OpenAI、Hugging Face、ML/AI エコシステム | Elasticsearch、Apache Spark、データエンジニアリング |
JSONL(JSON Lines)とは?
JSONL は JSON Lines の略で、各行に単一の有効な JSON 値を含むテキストベースのデータ形式です。行は改行文字(\n)で区切られます。このフォーマットは機械学習やデータサイエンスコミュニティで普及し、jsonlines.org で非公式に定義されています。
JSONL ファイルは .jsonl ファイル拡張子を使用します。このフォーマットは AI および ML のトレーニングデータの標準となっており、OpenAI はファインチューニングに .jsonl ファイルを必要とし、Hugging Face データセットでも JSON Lines フォーマットが一般的に使用されています。
{"id": 1, "text": "Hello world", "label": "greeting"}{"id": 2, "text": "How are you?", "label": "question"}{"id": 3, "text": "Goodbye", "label": "farewell"}
NDJSON(Newline Delimited JSON)とは?
NDJSON(Newline Delimited JSON)は、各行が改行文字で区切られた有効な JSON 値であるデータ形式です。仕様は github.com/ndjson/ndjson-spec でホストされており、行区切り JSON データのより構造化された標準を提供するために正式化されました。
NDJSON ファイルは .ndjson ファイル拡張子を使用し、application/x-ndjson という登録された MIME タイプを持っています。このフォーマットはデータエンジニアリング、ログ処理、ストリーミングアプリケーションで広く採用されており、Elasticsearch、Apache Spark、多くの HTTP ストリーミング API で NDJSON が使用されています。
{"id": 1, "text": "Hello world", "label": "greeting"}{"id": 2, "text": "How are you?", "label": "question"}{"id": 3, "text": "Goodbye", "label": "farewell"}
JSONL と NDJSON は同じフォーマットですか?
実際には、はい — JSONL と NDJSON は機能的に同一のフォーマットです。どちらも 1 行に 1 つの JSON 値を保存し、改行文字(\n)で区切ります。.jsonl ファイルと同じデータを含む .ndjson ファイルは完全に互換性があり、一方のフォーマットを読み込めるツールはもう一方も読み込めます。
違いは純粋に命名、コミュニティの採用、メタデータ規約にあります。JSONL(JSON Lines)はデータサイエンスと機械学習コミュニティから生まれ、NDJSON(Newline Delimited JSON)はデータエンジニアリングと Web ストリーミングコミュニティによって正式化されました。「movie」と「film」のようなもので、異なるサークルで異なる名称が好まれるだけで、同じものです。
最も意味のある違いは、ファイル拡張子(.jsonl vs .ndjson)と MIME タイプです。NDJSON は HTTP ストリーミングコンテキストで使用されるより広く認識された MIME タイプ(application/x-ndjson)を持ち、JSONL ファイルは AI/ML ワークフローの標準です。どちらを選択するかは、エコシステムの慣習に従ってください。
JSONL と NDJSON の主な違い
1. 仕様と権威
jsonlines.org で簡潔で非公式な仕様として定義されています。仕様は明快です:各行は有効な JSON 値、行は '\n' で区切られ、UTF-8 エンコーディングが推奨されます。
github.com/ndjson/ndjson-spec でやや正式な仕様として定義されています。NDJSON は、各行が有効な JSON 値であり、行区切り文字が '\n'('\r\n' ではない)であることを明示的に要求し、末尾の改行を推奨しています。
2. ファイル拡張子
.jsonl ファイル拡張子を使用します。これは OpenAI ファインチューニングファイル、Hugging Face データセット、ほとんどの ML/AI ツールの標準です。GitHub と VS Code は .jsonl ファイルを構文ハイライト付きで認識します。
.ndjson ファイル拡張子を使用します。これはデータエンジニアリングツール、Elasticsearch バルク API、ストリーミング HTTP レスポンスで一般的です。多くのエディタも .ndjson 構文ハイライトをサポートしています。
3. MIME タイプ
公式に登録された MIME タイプはありません。一般的な非公式タイプには application/jsonl や application/json-lines があります。実際には、多くのシステムが application/jsonl を使用するか、application/json にフォールバックします。
application/x-ndjson を MIME タイプとして使用します。これは HTTP コンテキストでより広く認識されており、Elasticsearch、Fetch API ストリーミング標準、さまざまな Web フレームワークでストリーミングレスポンスに使用されています。
4. コミュニティとエコシステムの採用
AI/ML エコシステムで支配的です。OpenAI、Anthropic、Google Gemini、Hugging Face、ほとんどの ML フレームワークが .jsonl を使用します。「JSONL」という用語は全体的に開発者コミュニティでより一般的に検索され、認識されています。
データエンジニアリングとバックエンドシステムで好まれます。Elasticsearch、Apache Spark、PostgreSQL COPY、多くのログ集約ツールが NDJSON を使用します。ndjson npm パッケージは毎週数百万回ダウンロードされています。
JSONL と NDJSON をいつ使うか
- OpenAI、Anthropic、その他の LLM ファインチューニング用のトレーニングデータを準備する場合
- Hugging Face データセットを扱う場合
- ML パイプラインとデータ前処理を構築する場合
- チームやドキュメントが「JSON Lines」を参照している場合
- .jsonl 拡張子を期待する AI/ML プラットフォームにファイルをアップロードする場合
- Python データサイエンス環境で作業する場合
- HTTP 経由で JSON データをストリーミングする場合(Server-Sent Events、fetch ストリーミング)
- Elasticsearch バルク API を扱う場合
- Apache Spark または類似ツールでデータパイプラインを構築する場合
- Content-Type ヘッダーを設定する場合(application/x-ndjson)
- インフラストラクチャやチームが NDJSON 規約を使用している場合
- Node.js ストリーミングライブラリを扱う場合
コード例:JSONL と NDJSON の読み込み
# JSONL の読み込み - NDJSON の読み込みと完全に同じimport jsonwith open('data.jsonl', 'r') as f:for line in f:record = json.loads(line.strip())print(record['text'])# 出力:# Hello world# How are you?# Goodbye
// NDJSON の読み込み - JSONL の読み込みと完全に同じimport { createReadStream } from 'fs';import { createInterface } from 'readline';const rl = createInterface({input: createReadStream('data.ndjson')});for await (const line of rl) {const record = JSON.parse(line);console.log(record.text);}// 出力:// Hello world// How are you?// Goodbye