TSV to JSON Converter

Turn a tab-separated export into objects a program can use. The separator is pinned so a comma-heavy file still parses, and each column gets one type.

To convert TSV to JSON, paste your tab-separated text or drop the file above. The header row becomes the keys, each line becomes one object, and each column is given a single type decided from all of its values. Empty cells become null. Choose a pretty array, a minified one, or JSON Lines.

Want to reshape it first? Open the app

Where tab-separated files come from

Three sources dominate. Bioinformatics and scientific tooling, where TSV is the default and files are large. Database export commands, several of which write tabs unless told otherwise. And the clipboard, because copying cells out of any spreadsheet gives you tab-separated text.

That third one is worth noticing: you can select a block of cells in Excel or Google Sheets, paste it straight into the box on this page, and get JSON without a file ever existing.

Tab-separated, declared rather than guessed

Most converters sniff the delimiter by counting candidates in the first few lines. That works until it does not, and when it fails it fails completely: a tab-separated export whose first rows hold several commas each gets read as a CSV, and every row comes back as one column of text with tabs inside it.

Because this page declares tab-separated input, the separator is pinned rather than sniffed. A file full of commas, semicolons and pipes still splits on tabs, which is what the file says it is.

That is the whole argument for having a TSV page distinct from the CSV one. Everything else about the two is the same; the difference is that this one cannot guess wrong.

Worked example

A tab-separated export, tabs shown as gaps:

store_code    city              staff   revenue   active
0041          Osaka, Japan      12      1840.50   true
0058          Berlin            7                 false

And the JSON:

[
  {
    "store_code": "0041",
    "city": "Osaka, Japan",
    "staff": 12,
    "revenue": "1840.50",
    "active": true
  },
  {
    "store_code": "0058",
    "city": "Berlin",
    "staff": 7,
    "revenue": null,
    "active": false
  }
]

store_code is a string because of the padded zero. city contains a comma and is completely unremarkable, which is the point of tabs. revenue is a string because 1840.50 does not round trip as a number, and the empty cell in that column is null rather than an empty string. active is a real boolean.

One type per column

The type is decided once for the whole column, from every value in it. A column is numeric only when every non-empty value round trips exactly, boolean only when every value is a lowercase true or false, and text otherwise.

That rule is what prevents the most common defect in generated JSON: the same key being a number in one object and a string in the next, which any schema validator and most typed clients reject outright.

It is also why a value like 1840.50 keeps the whole column as text. Writing it back as a number gives 1840.5, a different string, and a price column that has quietly lost a trailing zero on half its rows is worse than one that is text throughout.

What the conversion tells you about the file

A tab-separated file is easy to produce badly, because nothing in the format forces consistency. Rows drift in width when a field was optional, a header cell is left blank, a column name is repeated after two exports were joined.

All three are handled and all three are reported. A short row is padded to the header width and counted. A blank header cell is named by position so the column survives into the JSON instead of vanishing. A repeated header is renamed, so a second column called total becomes total_2 rather than overwriting the first when the row becomes an object.

That last one is worth dwelling on, because it is silent everywhere else. Two columns with the same name produce a JSON object with one key, and the value you get is whichever column came last. You lose a column and nothing tells you.

Arrays, lines, and the size question

  • A pretty array is the default and is what a fixture file, an API request body or a code review wants.
  • Minified is the same data with the whitespace gone, for shipping.
  • JSON Lines emits one compact object per line with no wrapping array, which is what warehouse loaders and log shippers want and what streams without holding the document in memory.
  • Every object carries every key, including the null ones, so the shape does not change from record to record.
  • No row cap. The widget takes files up to 100 MB, which for a typical TSV is well over a million lines, and nothing is uploaded at any size.

Frequently Asked Questions

My TSV is full of commas. Will it parse correctly?

Yes. The tab is pinned rather than sniffed on this page, so a file whose values contain commas, semicolons or pipes still splits on tabs. A delimiter heuristic counting candidates in the first few lines is exactly what fails on files like that.

Why is my revenue column a string?

Because a value in it does not round trip. 1840.50 as a JSON number is 1840.5, a different string, so the whole column stays text rather than half the rows quietly losing a trailing zero.

Do empty cells become null?

Yes, real nulls rather than empty strings, and the key is still present on every object. A missing key and a null value mean different things to a typed consumer.

Are types consistent across every object?

Always. A type is decided once per column from all of its values, never per cell. The alternative is the same key arriving as a number in one object and a string in the next, which any schema check rejects.

Can I paste cells from a spreadsheet directly?

Yes. Copying a block of cells from Excel, Numbers or Google Sheets puts tab-separated text on the clipboard, so you can paste it here and get JSON without any file existing.

Can I get one object per line?

Yes, the Structure switch emits JSON Lines: one compact object per line with no wrapping array. That is what bulk loaders want and what lets a large file stream rather than being held in memory.

Turn the export into typed objects

Tab pinned, one type per column, real nulls. Paste or drop and copy.

Back to the converter