TSV Files: What They Are and How to Create Them
Learn what TSV files are, how to open and create them in spreadsheets and Python, and how to avoid delimiter, encoding, and import errors.
TSV means tab-separated values. It is a plain-text table format: each line is a row, and a literal tab character separates the fields in that row. A header row is optional, but every record should use the same column order and field count.
For example, the following file contains three columns and two records. Each <TAB> marker represents one literal tab character, not the four letters shown:
name<TAB>department<TAB>email
Ada Lovelace<TAB>Analytical Engine<TAB>ada@example.com
Grace Hopper<TAB>Computing<TAB>grace@example.com
Save it as people.tsv using UTF-8, then configure the program that opens it to use Tab as the delimiter. TSV is simple and portable, but programs differ in how they treat quoting, embedded tabs, newlines, encodings, dates, and leading zeros. Test the exact producer and importer combination used by your workflow.
What is a TSV file?
A TSV file is delimiter-separated plain text:
- One line represents one table row.
- Tab characters separate columns.
- A first line may contain column names.
- The file can be read by text editors, spreadsheets, scripts, databases, and command-line tools.
TSV has no single universal specification covering every edge case. The Python csv documentation describes the module as implementing classes for tabular data and provides the excel_tab dialect for Excel-style tab-delimited files. RFC 4180 formally discusses CSV rather than TSV, but its description of differing producer and consumer behavior is useful context for delimiter-separated formats.
TSV versus CSV
| Question | TSV | CSV |
|---|---|---|
| Column delimiter | Tab character | Usually comma, though implementations may use another delimiter |
| Human readability | Columns are separated by wider whitespace in many editors | Commas are visible and can collide with ordinary prose |
| Spreadsheet support | Supported through text-import dialogs | Usually supported directly, with delimiter and encoding choices |
| Embedded delimiters | A tab inside a value must be escaped or quoted according to the shared format rules | A comma inside a value generally requires quoting |
| Best fit | Simple exports, scripts, and pipelines where tabs are unlikely in values | Interchange with systems that explicitly expect comma-separated data |
Neither format automatically preserves spreadsheet types. An importer may convert dates, long numbers, or identifiers with leading zeroes. Treat the delimiter, encoding, quoting rules, and type-conversion behavior as part of your interface contract.
How to open a TSV file
Open it as text
A text editor shows the raw tabs and line breaks. This is useful for checking whether the file really contains tab characters, whether rows have the expected number of fields, and whether non-ASCII characters survived export.
Open it in LibreOffice Calc
- Open Calc and choose File → Open.
- Select the
.tsvfile. If it is not listed, choose the text or CSV file type. - In the Text Import dialog, select Separated by and check Tab. Clear comma, semicolon, and space unless the file intentionally uses them too.
- Choose the file encoding, normally UTF-8.
- Inspect the preview. Confirm that each field is in the intended column, then open the file.
LibreOffice documents text CSV as one record per line and allows Tab to be selected as the field delimiter. Its menu labels and defaults can vary by version, so verify the preview and re-save a copy before changing the original.
Open it in Excel or another spreadsheet
The workflow is similar: use the text import or data-from-text command, choose Tab as the delimiter, select UTF-8 when offered, and inspect the preview. If identifiers such as 00123 must remain strings, set that column to Text during import instead of accepting automatic numeric conversion.
How to create a TSV file in a spreadsheet
- Enter or paste the table into the spreadsheet.
- Choose the program’s text-delimited or CSV export command.
- Select Tab as the field separator.
- Select UTF-8 (or the encoding required by the receiving system).
- Save with a
.tsvextension if the consumer uses the suffix to identify the format. - Re-open the exported file in a text editor or import it into a new sheet to verify the result.
Do not rely on the visible spreadsheet alone. Export can change line endings, quote fields, or convert values. Check a row containing non-ASCII text, a leading-zero identifier, a date, and an empty field.
Create TSV with Python
Python’s standard library is sufficient. Open files with newline='' and an explicit encoding so the csv module can handle row endings consistently.
import csv
rows = [
['name', 'department', 'email'],
['Ada Lovelace', 'Analytical Engine', 'ada@example.com'],
['Grace Hopper', 'Computing', 'grace@example.com'],
]
with open('people.tsv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f, dialect='excel_tab')
writer.writerows(rows)
If you want the delimiter to be explicit rather than relying on a named dialect, use delimiter='\t':
import csv
with open('people.tsv', 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f, delimiter='\t', lineterminator='\n')
writer.writerow(['name', 'department', 'email'])
writer.writerow(['Ada Lovelace', 'Analytical Engine', 'ada@example.com'])
Read TSV with Python
import csv
with open('people.tsv', 'r', newline='', encoding='utf-8') as f:
reader = csv.reader(f, dialect='excel_tab')
for row_number, row in enumerate(reader, start=1):
print(row_number, row)
For named columns, use DictReader:
import csv
with open('people.tsv', newline='', encoding='utf-8') as f:
for person in csv.DictReader(f, dialect='excel_tab'):
print(person['name'], person['email'])
Validate the field count when the input is external:
import csv
expected_columns = 3
with open('people.tsv', newline='', encoding='utf-8') as f:
for line_number, row in enumerate(csv.reader(f, dialect='excel_tab'), start=1):
if len(row) != expected_columns:
raise ValueError(f'line {line_number}: expected {expected_columns} fields, got {len(row)}')
Create TSV with Node.js
For simple data without embedded tabs or newlines, joining escaped fields is enough. Replace tabs and line breaks or adopt a documented quoting convention before writing untrusted values.
import { writeFile } from 'node:fs/promises';
const rows = [
['name', 'department', 'email'],
['Ada Lovelace', 'Analytical Engine', 'ada@example.com'],
['Grace Hopper', 'Computing', 'grace@example.com'],
];
const tsv = rows.map(row => row.join('\t')).join('\n') + '\n';
await writeFile('people.tsv', tsv, 'utf8');
Use TSV from the command line
To download a TSV file from a URL, preserve the response bytes and inspect the result before importing it:
curl -L 'https://example.com/data.tsv' -o data.tsv
For local inspection, commands such as head and cat -vet can reveal row boundaries and tabs on Unix-like systems:
head -n 5 people.tsv
cat -vet people.tsv
The second command commonly displays a tab as ^I; its exact output depends on the platform.
Formatting rules and edge cases
Tabs and newlines inside values
A literal tab looks like a column separator, and a newline looks like the end of a row. If a value can contain either character, agree with the receiving program on quoting or escaping. Python’s csv writer and reader can handle quoted fields, but a consumer that merely splits each line on \t cannot.
Empty fields
Two adjacent tabs represent an empty field. Preserve trailing empty fields according to the consumer’s rules; some simplistic parsers drop them.
Headers
Headers are optional. If present, document their names and order. If absent, document the positional meaning of each column.
Encoding
UTF-8 is a practical default. Confirm that the importer uses the same encoding, especially for accented names, non-Latin scripts, and symbols. A file that looks correct in one editor can still be decoded incorrectly elsewhere.
Line endings
Windows, macOS, and Linux tools may write different newline conventions. Most modern readers handle them, but strict pipelines may not. Re-open the exported file in the target system and check the final line as well as the first few lines.
Spreadsheet type conversion
Importers may turn 2026-10-01 into a date, 00123 into 123, or a long identifier into scientific notation. Set sensitive columns to Text during import and verify values after loading.
TSV troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Everything appears in one column | The importer is using comma or another delimiter | Choose Tab as the only separator and check the preview |
| Columns shift on some rows | A value contains an unescaped tab, or a field is missing | Inspect the offending row; quote or encode embedded tabs and validate field counts |
| Rows break unexpectedly | A value contains an unescaped newline | Use a writer/reader that supports quoting, or remove and encode embedded newlines |
| Accents display as garbled characters | Encoding mismatch | Export as UTF-8 and select UTF-8 during import |
| Leading zeroes disappear | Spreadsheet automatic numeric conversion | Import the column as Text |
| Dates change format or value | Spreadsheet date inference | Import as Text when exact text matters, then convert deliberately |
| Last column is missing | Trailing empty fields were discarded | Use a standards-aware parser and test rows ending in an empty field |
| Python emits blank lines on Windows | File was not opened with newline='' |
Pass newline='' to open() for both reading and writing |
Reliability, performance, and cost notes
- Reliability: Record the delimiter, encoding, newline policy, header presence, and quoting rules with the file contract. Validate every row before loading it.
- Performance: TSV is streamable. Python’s
csv.readerprocesses rows incrementally, so you do not need to load a large file into memory. Avoid repeatedly opening and closing the file inside a row loop. - Cost: TSV itself has no software or network fee. Costs come from the spreadsheet, storage, transfer, or processing system around it.
- Security: Treat imported values as data. Some spreadsheet applications interpret cells beginning with characters such as
=as formulas. Apply the receiving application’s CSV/TSV security guidance when exporting untrusted content.
Or skip the browser setup
If the reason you are preparing TSV data is to document or archive a web page, ScreenshotNeo can capture the page with one request instead of maintaining browser automation. See the ScreenshotNeo API documentation for all options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.
Create your free ScreenshotNeo account.
FAQ
Does a TSV file require a header?
No. A header is optional; document the positional meaning of columns when you omit one.
Can I rename a CSV file to TSV?
Only if its fields are actually separated by tabs and its quoting rules match the importer. Changing the extension alone does not change delimiters.
What delimiter should I select when opening a TSV?
Select Tab. Do not also select comma, semicolon, or space unless the producer explicitly used multiple delimiters.
Is TSV better than CSV?
It depends on the consumer. TSV can reduce collisions with commas in prose, while CSV may be the required interface for another system. Choose the format the receiving program documents and test edge cases.
How do I preserve leading zeros?
Import the column as Text or quote and validate it with the target application. Do not assume a spreadsheet will preserve an identifier as text automatically.


