What it is
JSON is the most common way to write structured data as text: objects in braces, lists in brackets, keys and values in quotes. JSONL, also called JSON Lines or newline-delimited JSON, adds one rule on top: each line of the file is one complete, valid JSON value, and lines are separated by a line break. For training data, each value is an object holding one example.
{"messages":[{"role":"system","content":"You are…"},{"role":"user","content":"How do I reset my password?"},{"role":"assistant","content":"Open Settings → Security…"}]}{"messages":[{"role":"user","content":"Hi"},{"role":"assistant","content":"Hello! How can I help?","weight":0},{"role":"user","content":"Export my report as PDF"},{"role":"assistant","content":"Open the report, click Export → PDF…","weight":1}]}{"messages":[{"role":"system","content":"You are…"},{"role":"user","content":"Can I change my plan mid-month?"},{"role":"assistant","content":"Yes. The difference is prorated…"}]}one line per record, no commas between lines, no surrounding [ ]{ … }one complete JSON object = one training record"messages"the conversation, in order"role"who said it: system, user or assistant"weight"learn this reply (1) or only read it (0)\na line break ends the recordWhy training uses it
- Streaming: a provider can read a multi-gigabyte file one line at a time instead of loading and parsing it whole.
- Independence: records can be counted, shuffled, split into training and validation, or sampled without parsing the rest of the file.
- Clear errors: a malformed record breaks one line, and the error message can name it (“line 482: unexpected end of input”).
- Appendable: adding examples means adding lines; nothing else in the file changes.
The rules, and how files break
The JSON Lines specification has three rules: the file is UTF-8, each line is a valid JSON value, and each line ends with a line-feed character. Ending the file with a line break is strongly recommended. Almost every broken training file breaks one of those rules:
✗ {"messages": [ ... ← a pretty-printed object split over lines
{"role": "user", ... } ]}
✗ [ {"messages": ...}, {"messages": ...} ] ← a JSON array, not one object per line
✗ {"messages": [...]}, ← trailing comma
✗ ← a blank line in the middle
✓ {"messages":[...]} ← one complete object, then a line breakLine breaks inside the text of a message are fine, because JSON stores them escaped (as a backslash followed by n) inside the string. What may not happen is a real line break in the middle of an object — which is exactly what “pretty-printing” a file for readability does.
Same format, different shapes
Every major fine-tuning service accepts JSONL, but each defines its own schema for what goes inside a line. Some use a messages list with system, user and assistant roles; some put the system prompt in a separate field; some call the list contents and the assistant role model; some support a weight on each assistant message so that earlier replies are context only.
// chat "messages" (with an optional weight per assistant reply)
{"messages":[{"role":"user","content":"Hi"},{"role":"assistant","content":"Hello!","weight":0},{"role":"user","content":"Export as PDF"},{"role":"assistant","content":"Open the report, click Export → PDF.","weight":1}]}
// "contents" with user / model roles
{"contents":[{"role":"user","parts":[{"text":"Export as PDF"}]},{"role":"model","parts":[{"text":"Open the report, click Export → PDF."}]}]}
// separate system field
{"system":"You are a support assistant.","messages":[{"role":"user","content":"Export as PDF"},{"role":"assistant","content":"Open the report, click Export → PDF."}]}Where a format has no per-message weight, a multi-turn conversation with several targets is written as one record per target, each cut off right after its target reply. In those records the earlier assistant replies are learned too, since the format has no way to mark them as context only.
- A conversation has four messages: “Hi”, a greeting, “Export my report as PDF”, and the instructions. Only the instructions are marked as a target.
- For a provider that supports weights: one line, with the greeting at
weight: 0and the instructions atweight: 1. - For a provider without weights: also one line, ending at the instructions. Had the greeting been a target too, there would be two lines — one ending at the greeting, one at the instructions — and the greeting would be learned twice.
- Both files contain the same cleaned, redacted text. Only the wrapping differs.
Common mistakes
- Pretty-printing a training file so each object spans several lines.
- Saving a JSON array of records and naming it .jsonl.
- Hand-editing a file in a tool that changes the encoding or adds smart quotes, which breaks the JSON.
- Reusing one provider's file with another provider: the format is the same, the schema inside is not.
References and further reading
External sources open in a new tab.
- 01JSON Linesjsonlines.org · jsonlines.orgThe short specification: UTF-8, one value per line, a line feed between them.
- 02RFC 8259: The JavaScript Object Notation (JSON) Data Interchange FormatIETF · RFC Editor · rfc-editor.orgThe JSON standard itself, including how strings escape line breaks.
- 03Supervised fine-tuningOpenAI API docs · developers.openai.comThe chat `messages` shape.
- 04Prepare supervised fine-tuning data for Gemini modelsGoogle Cloud documentation · docs.cloud.google.comThe `contents` shape with user and model roles.
- 05Prepare data for fine-tuning your modelsAmazon Bedrock User Guide · docs.aws.amazon.comShapes with a separate system field, plus per-model limits.