pandas to_csv(): Export DataFrames to CSV Correctly

Quick answer: DataFrame.to_csv() writes tabular data to a CSV path or file-like object. Reliable exports make the index, selected columns, delimiter, encoding, missing-value representation, and line endings deliberate. CSV is a text interchange format, so the writer’s choices must match the program that will read the file.

Python Pool infographic showing pandas DataFrame columns index header separator and CSV export options
DataFrame.to_csv() is easiest to reason about when the index, columns, delimiter, encoding, and destination are chosen explicitly.

DataFrame.to_csv() is the pandas method for exporting a DataFrame to a CSV file or to a CSV-formatted string. CSV files are plain text, easy to share, and supported by spreadsheets, databases, notebooks, and many data tools.

The important details are choosing whether to write the row index, where to save the file, how to represent missing values, and whether you need to append to an existing CSV. The examples below were tested with pandas 2.2.3 and follow the current pandas DataFrame.to_csv documentation.

Basic pandas to_csv example

If you call to_csv() without a file path, pandas returns the CSV text as a string. This is useful for learning the output format or sending data to another service without creating a file first.

<div class="pythonpool-code-scroll" style="max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;">import pandas as pd

df = pd.DataFrame({
    "Name": ["David", "Robert"],
    "Age": [20, 30],
    "City": ["Seattle", "Chicago"],
})

csv_text = df.to_csv(index=False)
print(csv_text)</div>
Name,Age,City
David,20,Seattle
Robert,30,Chicago

The index=False argument is usually what beginners want. Without it, pandas writes the DataFrame index as the first CSV column. That index is useful in some data workflows, but it often creates an unwanted blank-looking column when the file is opened in a spreadsheet.

Save a DataFrame to a CSV file

To save a real file, pass a file path as the first argument. A pathlib.Path object works well because it keeps path handling explicit and avoids many filename mistakes.

<div class="pythonpool-code-scroll" style="max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;">from pathlib import Path
import pandas as pd

df = pd.DataFrame({
    "Name": ["David", "Robert"],
    "Age": [20, 30],
    "City": ["Seattle", "Chicago"],
})

output_path = Path("people.csv")
df.to_csv(output_path, index=False)</div>

If the file is not created where you expect, print the resolved path or check the current working directory. The same path debugging rules from our Python rename file guide apply here too.

Select columns and handle missing values

You do not always need every DataFrame column in the exported CSV. Use columns to control the output order and na_rep to choose the text written for missing values.

<div class="pythonpool-code-scroll" style="max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;">summary = pd.DataFrame({
    "Name": ["David", "Robert"],
    "Score": [92.5, None],
    "Internal ID": [101, 102],
})

summary.to_csv(
    "scores.csv",
    index=False,
    columns=["Name", "Score"],
    na_rep="NA",
)</div>

This writes only the Name and Score columns. The missing score becomes NA instead of an empty field, which makes the CSV easier to review and safer for tools that treat empty values differently.

Python Pool infographic showing a pandas DataFrame, index, columns, and CSV export
DataFrame: A pandas DataFrame, index, columns, and CSV export.

Append rows to an existing CSV

Use mode="a" to append rows to an existing file. When appending, set header=False after the first write so the column names are not repeated in the middle of the CSV.

<div class="pythonpool-code-scroll" style="max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;">first = pd.DataFrame({"Name": ["Ana"], "Score": [88]})
second = pd.DataFrame({"Name": ["Bo"], "Score": [91]})

first.to_csv("scores.csv", index=False)
second.to_csv("scores.csv", mode="a", header=False, index=False)</div>

Appending is convenient for small logs and batch exports. For larger pipelines, consider writing separate files per batch and combining them later, because repeated appends can make error recovery harder.

Common to_csv arguments

  • path_or_buf: file path, buffer, or None to return a string.
  • index: writes or skips the DataFrame index.
  • columns: exports only selected columns in the given order.
  • sep: changes the delimiter, such as " " for tab-separated output.
  • na_rep: text to use for missing values.
  • encoding: text encoding, commonly "utf-8" or "utf-8-sig" for some spreadsheet workflows.
  • mode: write mode, such as "w" for overwrite or "a" for append.

Verify the exported CSV

After writing an important CSV, read it back with pandas.read_csv() and check the shape, column names, and a few sample rows. This catches mistakes such as duplicated headers, wrong delimiters, unexpected indexes, and missing-value formatting before the file reaches someone else.

<div class="pythonpool-code-scroll" style="max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;">saved = pd.read_csv("people.csv")
print(saved.shape)
print(saved.columns.tolist())</div>
Python Pool infographic comparing path, sep, index, header, columns, and pandas to_csv
Export options: Path, sep, index, header, columns, and pandas to_csv.

When should you keep the index?

Use index=False when the index is just pandas’ default row numbering. Keep the index when it has real meaning, such as a timestamp, product ID, or user ID that identifies each row. If the index should become a named CSV column, call reset_index() first or use index_label so the exported file has a clear header.

This decision affects how the file will be imported later. A CSV with an unnamed index column often looks fine at first, but it can create duplicate row numbers or confusing extra columns when another person opens it in Excel, Google Sheets, or a database import tool.

CSV is not the same as Excel

A CSV file stores text rows and delimiters. It does not preserve formulas, cell colors, filters, merged cells, charts, or multiple worksheets. If you need spreadsheet formatting, export to an Excel file instead. Use CSV when portability matters more than presentation, especially for APIs, command-line tools, version control, and repeatable data processing.

Python Pool infographic comparing UTF-8, quoting, decimal, line endings, and CSV text
Encoding and quoting: UTF-8, quoting, decimal, line endings, and CSV text.

Common pandas to_csv errors

If to_csv() raises a file path error, confirm that the parent folder exists and that the script has permission to write there. If the output contains strange characters, specify an encoding explicitly. If the file has repeated header rows, check whether append mode is being used without header=False. If numbers or dates look different after opening the file in a spreadsheet, inspect the raw CSV text before assuming pandas wrote the wrong values.

Related Python guides

Official references

Choose The Destination And Index

Pass a path for a simple export or a file-like object when the surrounding program owns the stream. The index is not automatically a data column in every workflow, so set index=False when it is only pandas bookkeeping. Preserve it when it identifies records and give it a name.

import pandas as pd

frame = pd.DataFrame({"name": ["Ada", "Grace"], "score": [95, 98]})
frame.to_csv("scores.csv", index=False)
frame.to_csv("scores-with-index.csv", index=True, index_label="row_id")
Python Pool infographic testing round trips, missing values, formulas, paths, and validation
CSV checks: Round trips, missing values, formulas, paths, and validation.

Export Columns And Control The Separator

Use columns to define a stable output contract rather than exporting whatever order happens to be present. A comma is conventional, but tab-separated files and regional spreadsheet settings may require a different separator. Validate requested columns before writing so a renamed column fails clearly.

columns = ["name", "score"]
missing = set(columns) - set(frame.columns)
if missing:
    raise KeyError(f"missing columns: {sorted(missing)}")
frame.to_csv("selected.tsv", columns=columns, sep="\t", index=False)

Handle Encoding, Missing Values, And Dates

CSV has no native type system. Choose an encoding for the receiving application, decide how missing values should be represented, and format dates intentionally when a downstream system expects a fixed layout. Do not rely on a spreadsheet’s automatic type guesses for identifiers with leading zeroes.

frame = pd.DataFrame({"code": ["001", None], "created": pd.to_datetime(["2026-01-01", "2026-01-02"])})
frame.to_csv(
    "export.csv",
    index=False,
    encoding="utf-8",
    na_rep="",
    date_format="%Y-%m-%d",
)

Export Large DataFrames Carefully

For a large frame, keep the output format stable and consider compression, chunks, or a more typed format when CSV is not a requirement. A CSV export should be tested by reading a sample back with the same separator and encoding, then comparing expected columns and row counts.

frame.to_csv("scores.csv.gz", index=False, compression="gzip")
round_trip = pd.read_csv("scores.csv.gz", compression="gzip")
assert list(round_trip.columns) == list(frame.columns)
print(len(round_trip))

The official pandas DataFrame.to_csv() reference documents the complete parameter set. Treat the output options as part of an interface contract, especially when another service or spreadsheet consumes the file.

For related tabular exports, compare Python CSV reading, TSV parsing, and tabulating structured data when defining the format another program will consume.

Frequently Asked Questions

How do I save a pandas DataFrame as CSV?

Call df.to_csv() with a path or file-like object, then choose index, columns, encoding, and separator settings that match the receiving system.

How do I remove the pandas index from a CSV?

Pass index=False when the index is not a meaningful output column; otherwise preserve it deliberately and give it a clear name.

How do I export selected columns with pandas?

Pass a list of column names through the columns argument and validate that each requested column exists before exporting.

Why does a CSV look wrong after to_csv()?

Check delimiter, quoting, encoding, line endings, index output, and the program used to open the file rather than assuming the DataFrame changed.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted