Token cost of the same table in 8 formats
One dataset, generated from a fixed seed: 100 fake customer records with 8 columns (id, name, email, city, signup_date, plan, monthly_spend, active). Each format below holds exactly the same values. We checked that by parsing the YAML, CSV and TSV back and comparing them with the JSON. Token counts are for OpenAI's two current encodings, measured on 2026-10-26.
| Format | Characters | o200k_base tokens | vs CSV | cl100k_base tokens | vs CSV |
|---|---|---|---|---|---|
| TSV | 7,953 | 2,934 | 0.97× | 2,976 | 0.98× |
| CSV | 7,953 | 3,037 | 1.00× | 3,051 | 1.00× |
| JSON, column list + row arrays | 9,191 | 3,068 | 1.01× | 3,121 | 1.02× |
| Markdown table | 9,821 | 3,502 | 1.15× | 3,528 | 1.16× |
| JSON, minified | 16,397 | 5,043 | 1.66× | 5,097 | 1.67× |
| YAML | 15,996 | 6,065 | 2.00× | 6,091 | 2.00× |
| JSON, pretty (2-space indent) | 21,799 | 7,743 | 2.55× | 7,797 | 2.56× |
| XML (2-space indent) | 27,660 | 9,239 | 3.04× | 9,269 | 3.04× |
o200k_base is the encoding of GPT-4o, GPT-4.1, GPT-5 and the o-series; cl100k_base is GPT-4 and GPT-3.5 Turbo. Characters are Unicode code points. 26 of the 100 rows contain a non-ASCII name or city (for example Kraków, Spärck Jones).
What the numbers show
- Repeating keys is the biggest cost. Minified JSON writes all 8 column names on every row. Moving them into a single
"columns"list, so each row is a plain array, cut the count from 5,043 to 3,068 tokens: about 20 tokens per row, or 39%. That one change brings JSON within 1% of CSV. - Whitespace is the second. Pretty-printing the same JSON added 2,700 tokens (54%) over the minified version. Indentation and line breaks are tokens like any other text.
- YAML is not a token saver by default. It drops JSON's quotes and braces but puts every field on its own line, with an indent, the key and a colon. That came to 6,065 tokens: 22% fewer than pretty JSON, 20% more than minified JSON, and twice CSV.
- XML pays for every key twice. Opening and closing tags made it the most expensive format at 3.04× CSV.
- Some differences are too small to matter. TSV beat CSV by 3.4%, and the gap moves row by row (the row shown below is 31 tokens as CSV and 32 as TSV), so treat the two as equal. The two encodings differ by under 2% on every format, because this data is mostly ASCII.
Does the gap change with table size?
No. Header and wrapper overhead is paid once, so it disappears into the row cost quickly. These are o200k_base tokens per row, using the first 10, 100 and 1,000 rows from the same seed:
| Format | 10 rows | 100 rows | 1,000 rows |
|---|---|---|---|
| TSV | 31.0 | 29.3 | 29.3 |
| CSV | 32.0 | 30.4 | 30.4 |
| JSON, column list + row arrays | 33.2 | 30.7 | 30.7 |
| Markdown table | 38.7 | 35.0 | 35.0 |
| JSON, minified | 50.7 | 50.4 | 50.7 |
| YAML | 61.0 | 60.6 | 61.0 |
| JSON, pretty | 77.7 | 77.4 | 77.7 |
| XML | 94.6 | 92.4 | 92.4 |
At 1,000 rows the spread between CSV and pretty JSON is about 47,000 tokens. Multiply by your price per million input tokens to see whether it matters for your workload.
Where the tokens go in one row
Row 2 of the dataset, split into o200k_base tokens (each · separates two tokens):
| Format | Tokens | Split |
|---|---|---|
| CSV | 31 | 2·,·Donald· T·uring·,·donald·.t·uring·2·@example·.com·,S·ing·apore·,·202·6·-·04·-·11·,·enterprise·,·445·1·.·13·,true·↵ |
| JSON, minified | 51 | {"·id·":·2·,"·name·":"·Donald· T·uring·","·email·":"·donald·.t·uring·2·@example·.com·","·city·":"·Singapore·","·signup·_date·":"·202·6·-·04·-·11·","·plan·":"·enterprise·","·monthly·_sp·end·":·445·1·.·13·,"·active·":·true·}, |
The values cost about the same everywhere. The date 2026-04-11 is 6 tokens in both rows, and numbers are split into groups of up to three digits (445·1). What JSON adds is key names and punctuation: 20 extra tokens for this row's 8 fields, repeated on every row. You can see the same splits for any text by pasting it into the token counter and turning on “Highlight each token”.
Which format should you send to a model?
- Flat tables: CSV or TSV. They are the cheapest here and every model has seen plenty of them. If you start from JSON, the JSON to CSV converter flattens an array of objects in your browser.
- Nested data you must keep as JSON: minify it, and if the records share a shape, send a column list plus row arrays. Those two changes alone took this dataset from 7,743 to 3,068 tokens.
- Data a human edits by hand: YAML or pretty JSON reads better, but strip the formatting before it goes into a prompt.
- Avoid XML for bulk data unless a downstream system needs it.
- Shorter keys help every key-repeating format. JSON, YAML and XML pay for each column name on every row; CSV pays once.
One limit to keep in mind: this article measures cost, not comprehension. We did not test whether a model answers questions about a CSV as accurately as about the same data in JSON. If accuracy matters, run your own evaluation before switching formats for a production prompt.
Method and how to reproduce it
Everything above comes from one script, token-format-benchmark.mjs (Node 18 or later, no network access needed). To rerun it:
npm install [email protected]
node token-format-benchmark.mjs # prints both tables
node token-format-benchmark.mjs --write # also saves the 8 files to ./out/
- Data: 1,000 rows from a mulberry32 generator with seed
20261026. The main table is the first 100 rows. Names come from a fixed list of 20 first and 20 last names, cities from 16, plans from 4 with amounts in a range per plan, dates between 2024-01-01 and 2026-09-26. Distribution in the first 100 rows: 56 free, 22 pro, 17 team, 5 enterprise; 80 active. Emails use the reservedexample.comdomain. - Serializers: written by hand in the script, so no library defaults are involved. Numbers and booleans are written the same way in every format (
49.5,true). CSV follows RFC 4180 quoting, which this data never triggers. YAML is a block sequence with dates left unquoted, the way people usually type them. Some YAML parsers load those as dates rather than strings. Markdown uses one space inside each pipe. XML and pretty JSON indent with 2 spaces. - Tokenizer: gpt-tokenizer 3.4.0, a JavaScript implementation of OpenAI's tiktoken encodings. Strings such as
<|endoftext|>are counted as plain text; the data contains none. We also ran every file through the copy of the same library that powers the token counter page and got identical counts. - Checks: the YAML (parsed with js-yaml 4.1.0), CSV and TSV (csv-parse 5.5.6) all parse back to exactly the minified JSON rows.
The script prints a SHA-256 of each file, so you can confirm you are counting byte-identical text. For the 100-row table:
| File | SHA-256 |
|---|---|
data.csv | 3794eec7e941a751712e8eca2f7fa71b58b5c0c640bc9bd4e8d969864102193b |
data.tsv | bd216e0dca5b97bba799417ce10c3dcb16b2580eccac578f6ca6998edb7ceba6 |
json-min.json | 8f7d01c208021a71e78f33c388978935539e565175df0fdc8c95d602b5208b86 |
json-pretty.json | 0cbe67cfc3e3fa71f6d3c9fd00499ed25ed637eeed8db0662e783727aa0d7e0f |
json-columnar.json | d978efcf9e0c6f73c54f29c91b7c9c57285d852a808d634d6f9b478dc1b21104 |
data.yaml | e69907d768502fc85eb0fdc8c76252b6346171580d05a660c673f399d35e92ee |
data.md | 92d716b177246bffa13259f6873a11623e3bf85308ae2b72a58332104bdaaa3d |
data.xml | fa21becae10ab29891a032525e95098d32a58a0b6c755a65ff7dc8e6998ecb41 |
Limits of this test. It is one dataset of short, mostly ASCII values. Tables with long free text will narrow the gaps, because the values dominate and cost the same in every format. Tables full of numbers or non-English text will shift them in ways we have not measured. Claude and Gemini use different tokenizers that are not public, so their ratios may differ.
Frequently asked questions
- Does YAML use fewer tokens than JSON?
- Only fewer than pretty-printed JSON. In our 100-row test, YAML took 6,065 o200k_base tokens, pretty JSON 7,743 and minified JSON 5,043. YAML puts every key on its own indented line, and the newline and indent cost tokens on every field, so YAML ends up costing about 20% more than minified JSON.
- How many tokens does one CSV row cost?
- In our table of 8 short columns (id, name, email, city, date, plan, amount, flag) a CSV row averaged about 30 o200k_base tokens, and the header row was 17. The per-row cost stayed flat from 10 to 1,000 rows. Rows with long text, many digits or non-English text cost more, so count a sample of your own data.
- Do Claude and Gemini show the same differences between formats?
- We did not measure them. Anthropic and Google do not publish the tokenizers their current models use, so the counts here cover OpenAI's o200k_base and cl100k_base only. The structural reasons, repeated keys and whitespace, apply to any tokenizer, but the exact ratios will differ. Anthropic's count_tokens endpoint and Google's countTokens method will measure your own files.
- How do I count the tokens in my own data file?
- Drop the .json, .csv, .md or .txt file into the larely token counter. It counts o200k_base and cl100k_base tokens in your browser without uploading the file, so you can compare two exports of the same data side by side. To reproduce this article's numbers exactly, run the published benchmark script with Node.
Sources
Format definitions are taken from their specifications; encoding details from OpenAI's tiktoken source. The token counts themselves are our own measurement, described in the method section.
- RFC 4180: Common Format and MIME Type for CSV Files: the quoting rules the CSV serializer follows
- RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format: JSON syntax, including that insignificant whitespace is allowed around structural characters (so it can also be left out)
- YAML Ain't Markup Language, version 1.2.2: block sequences and plain scalars as used in the YAML output
- W3C: Extensible Markup Language (XML) 1.0, Fifth Edition: element syntax and the escaping of
&,<and> - GitHub Flavored Markdown spec: tables extension: the pipe-table syntax used for the Markdown output
- OpenAI tiktoken,
model.py: which models use o200k_base and which use cl100k_base - gpt-tokenizer (MIT): the tokenizer used for the counts, version 3.4.0