Skip to main content
v2026.11,858 entries · CC-BY 4.0
LAC HealthMedical & Research SuppliesReagents, PPE & instruments — chain-of-custody documented.Fast, traceable sourcing built for regulated research environments, from bench consumables to instrumentation.Shop lac.us CodeCASRAIlac.us

R Write CSV: write.csv, write_csv and fwrite Compared

How to write a CSV in R with write.csv, readr write_csv or data.table fwrite, and how row names, NA, quoting and encoding defaults differ.

Written and maintained by CASRAI Editorial Board

Last updated

To write a CSV file in R, call write.csv(df, "out.csv", row.names = FALSE) in base R, readr::write_csv(df, "out.csv") in the tidyverse, or data.table::fwrite(df, "out.csv"). The three look alike but differ in defaults that change what lands in the file: whether row names are written, what a missing value looks like, how text is quoted, and how the file is encoded. This guide sets those defaults side by side, from each function’s own reference page.

What it is used for in research

Writing a data frame to CSV is the usual last step before a result leaves R: a cleaned analysis dataset deposited alongside a paper, a table of model estimates opened in a spreadsheet by a collaborator, or an export that another tool ingests. CSV is plain text, so the choices you make at write time (row names, missing-value string, encoding, delimiter) decide whether the next reader sees clean columns or a stray index column and garbled accents. If you are on the receiving end of such a file, see reading CSV into R.

Install or access (official source only)

write.csv() and write.csv2() live in the utils package, which is part of base R, so nothing needs installing. write_csv() comes from the readr package and fwrite() from the data.table package; install either from CRAN once, then load it:

install.packages("readr")
install.packages("data.table")
library(readr)
library(data.table)

New to package installation? See how to install R packages. For the wider picture of getting data in and out, see how to load data into R.

Step-by-step: write a data frame to CSV in R

Write a CSV with write.csv() in base R

  1. Have a data frame, here called df.
  2. Run write.csv(df, file = "out.csv", row.names = FALSE).
  3. Check the file in a text editor or reload it with read.csv("out.csv").

write.csv() calls write.table() with the CSV settings fixed: separator ,, decimal point ., and double quotes inside text values written as doubled quotes. The same help page notes that trying to change append, col.names, sep, dec or qmethod in a write.csv() call is ignored with a warning.

Write a CSV with write_csv() from readr

  1. Load readr with library(readr).
  2. Run write_csv(df, "out.csv"). The first argument must be a data frame or tibble.

readr documents that, unlike write.csv(), its writers do not include row names as a column in the file, so there is no row.names argument to set.

Write a CSV with fwrite() from data.table

  1. Load data.table with library(data.table).
  2. Run fwrite(df, "out.csv").

The data.table reference describes fwrite() as “As write.csv but much faster (e.g. 2 seconds versus 1 minute) and just as flexible,” and sets row.names = FALSE by default, unlike write.csv().

Defaults compared: what each writer puts in the file

Setting write.csv() (base R) write_csv() (readr) fwrite() (data.table)
Row names written Yes (row.names = TRUE) No row-names column No (row.names = FALSE)
Missing values (na) "NA" "NA" Empty string
Quoting Character and factor columns, and row and column names, in double quotes (quote = TRUE) quote = "needed" quote = "auto"
Encoding Set with fileEncoding All columns written as UTF-8 encoding = ""
Byte order mark Not an argument None (use write_excel_csv() to add one) bom = FALSE (set TRUE to add EF BB BF)
Date-times Not specified on the help page ISO 8601, converted to UTC dateTimeAs = "ISO"
Append to an existing file Ignored with a warning append = TRUE Not covered here

Output and how to read it

The extra first column from write.csv()

With the default row.names = TRUE, write.csv() writes the row names as the first column and sets col.names to NA, which adds a blank column name for that first column. The help page says this is the CSV convention expected by spreadsheets. To read such a file back without an extra column, use read.csv("out.csv", row.names = 1). If the row names are just 1, 2, 3 you do not need them: pass row.names = FALSE.

Quotes, missing values and numbers

Text and factor columns are wrapped in double quotes by write.csv(), and readr quotes only where needed. Numbers are written with up to 15 significant digits; the help page points to the scipen option, and suggests applying format() to a column first if you need finer control. In readr, missing values are never quoted, while a string that matches the na value is always quoted. Because fwrite() writes empty strings for missing values, a file written by fwrite() and one written by write.csv() show missing data differently when opened in a text editor. Related: replacing NA with 0 in R.

Troubleshooting

An unexpected first column appears when I reopen the file

That is the row-names column from write.csv(). Write with row.names = FALSE, or read with row.names = 1.

Why does write.csv() warn that sep or col.names was ignored?

Because write.csv() fixes sep, dec, qmethod, append and col.names; changing them is ignored with a warning. For a different delimiter call write.table() directly, which has sep as an argument.

Accented characters look wrong in Excel

readr states that write_csv() encodes every column as UTF-8 and adds no byte order mark. write_excel_csv() adds a byte order mark so that Excel reads the file as UTF-8. With fwrite() the same effect is bom = TRUE. In base R, fileEncoding declares the encoding used for a file.

My spreadsheet expects semicolons and decimal commas

Use write.csv2() in base R (separator ;, decimal ,) or write_csv2() in readr (semicolon delimiter). The TSV file guide covers the tab-separated alternative.

Can I add rows to an existing file?

With readr, write_csv(df, "out.csv", append = TRUE) appends, and col_names defaults to !append so the header is not repeated. write.csv() ignores append.

Alternatives to write.csv()

Function Package What the reference page says it does
write.csv() utils (base R) Passes arguments to write.table() with comma separator; adds a row-names column by default
write.csv2() utils (base R) Semicolon separator and decimal comma
write_csv() readr No row names; UTF-8; ISO 8601 date-times in UTC
write_excel_csv() readr Comma-delimited with a byte order mark so Excel reads UTF-8
write_csv2() readr Semicolon delimiter
fwrite() data.table Described as write.csv but much faster; no row names by default; missing values written empty

FAQ

How do I write a CSV in R?

Call write.csv(df, "out.csv", row.names = FALSE) for base R, or write_csv(df, "out.csv") after loading readr. Both write a data frame to a comma-separated text file.

What is the difference between write.csv in R and write.table?

write.csv() is write.table() with CSV settings fixed (comma separator, period decimal, doubled quotes), which is why changing sep in it is ignored.

How do I remove row names when I write.csv in R?

Set row.names = FALSE. The readr and data.table writers omit them by default.

How do I write a CSV in R without quotes?

In write.csv() set quote = FALSE; in readr set quote = "none". Without quoting, a value that contains a comma will split across columns when the file is read.

How do I append to a CSV in R?

Use write_csv(df, "out.csv", append = TRUE); write.csv() ignores append.

Sources (official docs)

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about R Write CSV: write.csv, write_csv and fwrite Compared

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →