How do I write multiple sheets to one Excel file with pandas?
Short answer
Use pd.ExcelWriter as a context manager and call to_excel once per sheet with a different sheet_name. Writing each frame to a separate file, or reopening the writer, are the mistakes that lose sheets.
The short version
Open a pd.ExcelWriter as a context manager and call to_excel once per sheet, giving each a different sheet_name. All the frames land in one workbook, saved when the with block ends. The usual mistakes are writing each frame to a separate file, or opening the writer without a context manager and forgetting to save.
The correct pattern
import pandas as pd
q1 = pd.DataFrame({"city": ["Leeds"], "sales": [100]})
q2 = pd.DataFrame({"city": ["Bath"], "sales": [80]})
with pd.ExcelWriter("report.xlsx") as writer:
q1.to_excel(writer, sheet_name="Q1", index=False)
q2.to_excel(writer, sheet_name="Q2", index=False)
Each to_excel writes to the same writer, so both sheets end up in report.xlsx. The with block saves and closes the file automatically at the end.
The mistake that loses sheets
Calling to_excel on a filename repeatedly does not add sheets; each call overwrites the whole file, so only the last survives.
# WRONG: the second call overwrites the first
q1.to_excel("report.xlsx", sheet_name="Q1")
q2.to_excel("report.xlsx", sheet_name="Q2") # report.xlsx now has only Q2
The shared ExcelWriter is what keeps the sheets together, because both writes target the same open workbook.
Turning off the index
Set index=False unless the DataFrame's index is meaningful, or you get an extra unlabelled column of row numbers in the sheet. This is the same habit as with CSV output.
Writing a dictionary of frames
If you have a dictionary mapping sheet names to DataFrames, loop over it.
sheets = {"Q1": q1, "Q2": q2}
with pd.ExcelWriter("report.xlsx") as writer:
for name, frame in sheets.items():
frame.to_excel(writer, sheet_name=name, index=False)
This scales to any number of sheets without repeating the write call by hand.
Positioning frames on a sheet
You can place several frames on the same sheet by setting startrow or startcol, which is useful for building a small report with a few tables stacked or side by side.
q1.to_excel(writer, sheet_name="summary", startrow=0, index=False)
q2.to_excel(writer, sheet_name="summary", startrow=len(q1) + 2, index=False)
Leaving a gap row between them keeps the tables visually separate.
The engine
Writing .xlsx uses the openpyxl engine, which pandas selects automatically if it is installed. If you get an error about a missing engine, install openpyxl. For appending to an existing workbook rather than replacing it, pass mode="a" and choose how existing sheets are handled with if_sheet_exists, though creating the file fresh is simpler when you can.