How to write a CSV file with pandas

Delimited text remains a common handoff between data analysis, spreadsheets, databases, and automation systems. A pandas DataFrame can become a CSV file with an explicit column order and text format that the receiving system can inspect without a Python runtime.

Pandas writes a DataFrame to a path, path-like object, file-like object, or an in-memory string through DataFrame.to_csv(). A path-based export leaves a file that can be inspected and read back, while index=False prevents the row labels from becoming an extra CSV column.

CSV preserves cell text rather than enforcing spreadsheet safety rules. Review values from untrusted sources for formula-leading equals, plus, minus, and at signs before sharing an export that someone will open in spreadsheet software.

Steps to write a CSV file with pandas:

  1. Create write_orders_csv.py with the initial output-path setup.
    write_orders_csv.py
    from pathlib import Path
     
    import pandas as pd
     
    output = Path("exports/orders.csv")
    output.parent.mkdir(parents=True, exist_ok=True)

    to_csv() does not create missing parent directories, so the output directory must exist before the export runs.

  2. Append the order data block below the output-directory setup in write_orders_csv.py.
    orders = pd.DataFrame(
        {
            "order_id": pd.Series(["A100", "A101", "A102"], dtype="string"),
            "customer": ["Ada Lovelace", "Lin Chen", "Maya Patel"],
            "region": ["EMEA", "APAC", "AMER"],
            "total_usd": [149.5, None, 212.0],
            "ordered_at": pd.to_datetime(
                ["2026-06-01", "2026-06-02", "2026-06-03"]
            ),
        }
    )
  3. Append the CSV export block below the DataFrame definition in write_orders_csv.py.
    orders.to_csv(
        output,
        sep=",",
        index=False,
        columns=["order_id", "customer", "region", "total_usd", "ordered_at"],
        na_rep="",
        float_format="%.2f",
        date_format="%Y-%m-%d",
        encoding="utf-8",
        lineterminator="\n",
    )
     
    print(f"Wrote {output}")

    columns fixes the export order, na_rep=“” leaves the missing total blank, and the format options make dates, decimal places, encoding, and line endings explicit.

  4. Run write_orders_csv.py to create the CSV file.
    $ python3 write_orders_csv.py
    Wrote exports/orders.csv
  5. Inspect the saved CSV text at exports/orders.csv.
    $ cat exports/orders.csv
    order_id,customer,region,total_usd,ordered_at
    A100,Ada Lovelace,EMEA,149.50,2026-06-01
    A101,Lin Chen,APAC,,2026-06-02
    A102,Maya Patel,AMER,212.00,2026-06-03

    The file should contain the selected header order, three data rows, one blank total, ISO-style dates, and two-decimal totals.
    Tool: Comma-Separated Values (CSV) Converter

  6. Read exports/orders.csv back with pandas to verify the exported table.
    $ python3 - <<'PY'
    from pathlib import Path
    
    import pandas as pd
    
    csv_path = Path("exports/orders.csv")
    round_trip = pd.read_csv(
        csv_path,
        dtype={"order_id": "string"},
        parse_dates=["ordered_at"],
    )
    
    expected_columns = [
        "order_id",
        "customer",
        "region",
        "total_usd",
        "ordered_at",
    ]
    
    assert round_trip.columns.tolist() == expected_columns
    assert round_trip["order_id"].tolist() == ["A100", "A101", "A102"]
    assert round_trip["total_usd"].isna().sum() == 1
    assert round_trip["ordered_at"].dt.strftime("%Y-%m-%d").tolist() == [
        "2026-06-01",
        "2026-06-02",
        "2026-06-03",
    ]
    
    print(round_trip.to_string(index=False))
    print(f"\nRows: {len(round_trip)}")
    print(f"Columns: {', '.join(round_trip.columns)}")
    print(f"Missing totals: {round_trip['total_usd'].isna().sum()}")
    PY
    order_id     customer region  total_usd ordered_at
        A100 Ada Lovelace   EMEA      149.5 2026-06-01
        A101     Lin Chen   APAC        NaN 2026-06-02
        A102   Maya Patel   AMER      212.0 2026-06-03
    
    Rows: 3
    Columns: order_id, customer, region, total_usd, ordered_at
    Missing totals: 1

    The read-back command fails if the file is missing, the schema changes, an order ID is altered, the missing total is lost, or a date no longer matches the expected value.