CSV File Documentation
Summary
A Comma-Separated Values file is a plain-text table: each line is one row, and the values in a row are separated by commas. It has been used since the 1970s and was written down as RFC 4180 in 2005, with the MIME type text/csv. Any spreadsheet or text editor opens a .csv file, so the usual questions are about the delimiter (comma vs semicolon) and character encoding.
Technical details
| Feature | Value |
|---|---|
| Full name | Comma-Separated Values |
| File extension | .csv |
| MIME type | text/csv |
| Format type | Plain-text tabular data |
| Developer | No single owner; documented by the IETF |
| Introduced | 1970s (early use); RFC 4180 published 2005 |
| Standard | RFC 4180 (informational) |
| Open standard | Yes — freely published, no licence |
| Delimiter | Comma (,); semicolon and tab variants in common use |
| Quote character | " (double quote, %x22) |
| Escape | A literal quote is doubled: "" |
| Line terminator | CRLF per RFC 4180; real files also use LF or CR |
| Multi-line fields | Yes, when the field is quoted |
| Header row | Optional; signalled by the header MIME parameter |
| Data types | None — every field is text |
| Encoding | Not declared by the format; UTF-8 is the modern norm |
| Byte-order mark | Optional UTF-8 BOM EF BB BF (Excel writes and reads it) |
| Byte order | n/a (text) |
| File signature | None |
| Related extensions | .tsv .xlsx .json .txt |
| Specification | rfc-editor.org/rfc/rfc4180 |
What is a CSV file?
CSV stands for Comma-Separated Values. It is a plain-text format for tabular data: one line per row, and the values in a row separated by commas. The idea is old. Programs were exchanging comma-delimited text in the early 1970s, and the convention outlived the machines it grew up on because it needs nothing more than a text file. In October 2005 the IETF wrote the common practice down as RFC 4180, which also registered the MIME type text/csv. RFC 4180 is informational, not a hard standard, and it says so plainly: it documents the format “that seems to be followed by most implementations,” not a format everyone obeys.
That caveat is the whole story of CSV. There is no owning vendor, no version number, and no header that declares the rules a given file follows. A .csv is text, and text carries no metadata about its own delimiter, its quoting, or its character set. Everything below describes the RFC 4180 grammar and then the places where real files drift away from it.
The RFC 4180 grammar: file, record, field
RFC 4180 defines the format with a short ABNF grammar. The whole thing fits in a dozen rules, which is a fair measure of how simple the format is:
file = [header CRLF] record *(CRLF record) [CRLF]
header = name *(COMMA name)
record = field *(COMMA field)
name = field
field = (escaped / non-escaped)
escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE
non-escaped = *TEXTDATA
COMMA = %x2C ; the comma ,
CR = %x0D ; carriage return
LF = %x0A ; line feed
DQUOTE = %x22 ; the double quote "
CRLF = CR LF
TEXTDATA = %x20-21 / %x23-2B / %x2D-7E
Read from the top: a file is an optional header line, then one or more records, each separated by a CRLF, with a trailing CRLF allowed at the end. A record is one or more fields joined by commas. A field is one of two shapes, escaped or non-escaped, and the difference between them is the quoting rule that the rest of this article turns on.
The TEXTDATA rule is worth a second look. It lists the byte ranges allowed in an unquoted field: %x20-21, %x23-2B, and %x2D-7E. Those ranges deliberately leave three characters out of the printable-ASCII set: the comma (%x2C), the double quote (%x22), and everything below space, which includes CR and LF. A field that needs any of those cannot be a bare non-escaped field; it must take the escaped form. Notice too that the grammar is defined entirely in the ASCII range. RFC 4180 has nothing to say about bytes above %x7E, which is exactly why non-English text is a problem, covered further down.
Records and the CRLF line terminator
In the grammar, records are separated by CRLF, the two-byte sequence carriage-return then line-feed (0D 0A). That choice reflects the format's origin on systems where CRLF was the line ending, and it is what the RFC prescribes.
Real files do not cooperate. A CSV written on Linux or macOS almost always ends its lines with a lone LF (0A); very old Mac tools used a lone CR (0D). All three appear in the wild, so a robust parser has to accept any of them as a record separator, not just the CRLF the standard names. This is the first of several points where “follow RFC 4180” and “read whatever people actually produce” pull in different directions. The ambiguity also interacts with quoting: a CR or LF is a legal character inside a quoted field, so a parser cannot simply split the file on newlines. It has to track whether it is currently inside quotes, and only treat a line break as a record boundary when it is not.
Fields, the comma delimiter, and significant spaces
Within a record, the comma separates fields, and nothing else does the job in the strict format. Two adjacent commas mean an empty field between them, and a comma at the end of a line means the last field is empty. The record a,,c has three fields, the middle one empty; a,b, has three fields with an empty third. There is no way to distinguish an empty field from a field holding an empty string, because the format has no types and no null: both are just zero characters between two delimiters.
One rule surprises people. RFC 4180 states that “spaces are considered part of a field and should not be ignored.” Leading and trailing spaces are significant. The field Alice with a space on each side is not the same as Alice, and a conforming writer must not trim them. Many tools trim anyway, which is another way real data drifts from the specification. If a value's surrounding spaces matter, the safe move is to quote the field so no reader is tempted to strip them.
Quoting with the double quote, and the doubled-quote escape
A field must be wrapped in double quotes when it contains any of the characters the grammar excludes from an unquoted field: a comma, a carriage return, a line feed, or a double quote. Inside a quoted field those characters lose their structural meaning and become plain data. That is how a value can itself contain a comma, or span several lines, without breaking the row.
The double quote needs its own escape, because a bare " inside a quoted field would otherwise look like the closing quote. RFC 4180 escapes it by doubling: a literal quote is written as two quotes, "". Here is a worked example. Suppose a row has four logical values — a name with a comma, a plain number, a note containing an embedded line break, and a quoted phrase:
Field 1 (name): Doe, John
Field 2 (age): 42
Field 3 (note): line one
line two
Field 4 (quote): she said "hi"
Encoded as one CSV record:
"Doe, John",42,"line one
line two","she said ""hi"""
Walking through it: field one is quoted because it holds a comma; field two is a bare number that needs no quoting; field three is quoted because it contains a real line break, so the record physically spans two lines in the file yet is still one logical row; field four is quoted because it contains double quotes, and each internal " is written as "". The trailing """ is the last data quote (doubled) plus the field's closing quote. A parser reconstructs the four original values by stripping the outer quotes and collapsing every "" back to a single ".
The table below summarises when a field has to be quoted.
| Field content | Must be quoted? | Reason |
|---|---|---|
Contains the delimiter (,) | Yes | An unquoted comma would start a new field |
| Contains a line break (CR or LF) | Yes | An unquoted line break would start a new record |
Contains a double quote (") | Yes, and each " is doubled to "" | A bare quote is ambiguous with the field terminator |
| Leading or trailing spaces that must survive | Recommended | Spaces are significant, but many readers trim unquoted ones |
| Plain text, numbers, no special characters | No | A bare (non-escaped) field is valid |
The optional header line and the header MIME parameter
The first line of a CSV may be a header that names the columns. In the grammar it is [header CRLF], an optional prefix with exactly the same shape as a record. Nothing in the file marks it as a header; it is a header only by agreement between whoever wrote the file and whoever reads it. A parser cannot tell a header row from a data row by looking at the bytes.
Because the file itself cannot say whether a header is present, RFC 4180 puts that information in the MIME type instead. The text/csv registration defines an optional header parameter with two values, present or absent, so a transfer can be labelled text/csv; header=present. In practice this parameter rarely travels with the file — a .csv on disk has no MIME type attached — so most tools fall back to a heuristic or simply ask the user whether the first row is a header.
Dialects: semicolon, tab and pipe, and why CSV is a family
“CSV” names a family of conventions more than one strict format, and the delimiter is where the family splits. The comma is the classic choice, but it collides with a widespread numeric convention: in much of continental Europe the comma is the decimal mark, so 3,14 is a single number, not two fields. Spreadsheets in those locales use a semicolon as the field separator instead, and a comma-delimited file opened there lands every row in one column. The reverse happens too.
Excel makes this locale-dependent by design: its list separator follows the operating system's regional settings rather than anything in the file, which is why the same .csv opens cleanly on one machine and as a single mangled column on another. Other separators show up as well. The tab character gives the TSV variant, which sidesteps the comma-versus-decimal clash because tabs rarely appear inside data. The pipe (|) is common in data-warehouse exports for the same reason. All of these are informally “CSV”; none of them is what RFC 4180 strictly describes.
| Delimiter | Character | Where you see it |
|---|---|---|
| Comma | , | RFC 4180 default; US/UK locales |
| Semicolon | ; | EU locales where comma is the decimal mark |
| Tab | \t | The TSV variant; database and scientific exports |
| Pipe | | | Data-warehouse and ETL exports |
Encoding, the BOM, and why numbers get mangled
A CSV declares no character set. The grammar is pure ASCII, and anything above byte 7E — an accented letter, a currency symbol, a Cyrillic or CJK character — is interpreted according to whatever encoding the reader guesses. Guess wrong and you get mojibake: text saved as UTF-8 but read as Windows-1252 turns café into café. There is no field in the format to prevent this, because the format has no fields for metadata at all.
The one in-band hint available is the byte-order mark. A file may begin with the three-byte UTF-8 BOM, EF BB BF, which is not really a “byte order” signal in UTF-8 but works as an encoding tag. Excel writes this BOM when it saves UTF-8 CSV and relies on it when opening one, which is why a UTF-8 file without the BOM often opens garbled in Excel while the same file with the BOM opens correctly. The BOM is optional, many CSVs omit it, and some other tools show it as stray characters at the start of the first field, so it is a fix and a nuisance at once.
Encoding is not the only data-integrity trap. Because every field is text with no declared type, the reader decides what a value “is,” and spreadsheets guess aggressively. A ZIP code like 07728 loses its leading zero when read as a number; a long credit-card or phone number turns into scientific notation such as 1.23457E+15; a value like 3-1 can be read as a date. None of this is the format's fault. The bytes on disk are correct; the loss happens when a typed application imports untyped text and guesses the type. Quoting does not prevent it, because the quotes are stripped on import. The reliable fix is on the reading side: import as text, or use the application's import wizard to set each column's type.
No types, no schema: CSV against XLSX and JSON
CSV stores values, and only values, as text. There is no schema, no type system, no notion of a formula, a cell format, a second sheet, or a nested structure. That flatness is the reason it moves so easily between systems, and also the reason it drops so much on the way out of a richer format.
Saving a spreadsheet as CSV keeps the plain contents of one sheet and discards everything that made it a spreadsheet. An XLSX workbook has typed cells, formulas, number formats, charts, and many sheets; exported to CSV, the formulas become their last computed values, the formatting disappears, and only the active sheet survives. Where CSV is a flat grid of strings, JSON carries typed values (numbers, booleans, null) and nests objects and arrays, so it represents hierarchy that CSV cannot express without inventing a convention on top. CSV is the lowest common denominator on purpose: what it lacks in structure it makes up for by being readable by essentially everything.
Frequently asked questions
Why does Excel put my whole row in one column?
The file uses a different delimiter than Excel expects for your region. Excel takes its field separator from the operating system's list-separator setting, so a comma-delimited file opened in a locale that expects a semicolon (or the reverse) is not split at all. Rather than double-clicking, use Data › From Text/CSV and pick the delimiter in the preview, or change the list separator in your regional settings.
Why are my accented characters garbled?
The file is one encoding and the app read it as another, usually a UTF-8 file opened as Windows-1252. CSV carries no encoding declaration, so the reader guesses. Re-open through the import wizard and choose UTF-8, or save the file with a UTF-8 BOM (EF BB BF) so Excel detects it automatically.
Is a semicolon-delimited file still a CSV?
In practice, yes. RFC 4180 defines the comma as the delimiter, so a semicolon file is not strictly conformant, but “CSV” is used loosely for the whole family of delimited text. Semicolon files are normal in European locales where the comma is the decimal mark. If you need to avoid the ambiguity entirely, a tab-delimited TSV is the cleaner choice.
References
- IETF RFC 4180 — Common Format and MIME Type for Comma-Separated Values (CSV) Files
- OWASP — CSV Injection
- Microsoft — Import or export text (.txt or .csv) files
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.