Skip to content
MegaRows

How to merge CSV files into one (with or without Excel)

By MegaRows · Published · 9 min read

Monthly exports, one file per sensor, a download split into parts: sooner or later you need several CSV files as one. For two tidy files that’s trivial. The trouble starts with repeated headers, columns in a different order, a missing final line break or a total too big for Excel. This guide compares six ways to merge CSV files and the pitfalls that break a merge.

Option 1: The MegaRows merge tool

The MegaRows merge tool is a free web page that combines CSV, TSV and TXT files. Your browser merges them on your own device, so nothing is uploaded.

  1. Add your files. Open the merge tool and drop two or more CSV, TSV or TXT files on it, in the order their rows should appear. Each file shows its separator and its number of rows and columns.
  2. Choose how to combine them. Pick Strict for files with identical columns, Union to keep every column from every file, or Column mapping to match columns whose names differ. Optionally add a source_file column or remove duplicate rows.
  3. Merge and download. Click “Merge & download”. The merged file is saved as merged.csv, and a summary shows the rows and columns written. In Chrome and Edge you can save it straight to disk.

Each file is read with its own separator, encoding (UTF-8, UTF-16 or Windows-1252) and decimal separator, quoted line breaks are respected, and missing final line breaks are added. Files with identical headers are appended unchanged, and big files are fast: two files of 2 million rows each merge in about half a second.

Pros: nothing to install; private; copes with different columns, separators and encodings; handles files far beyond Excel’s limit.

Cons: reads and writes CSV, TSV and TXT only (Excel files are coming soon); not scriptable for a nightly job.

Option 2: Windows Command Prompt and PowerShell

Command Prompt’s copy command joins files byte for byte. Run it in the folder that holds your CSV files and write the result one level up, so the output doesn’t match *.csv itself:

copy /b *.csv ..\merged.csv

/b copies the files as binary; without it, copy treats them as text and may stop at, or add, an end-of-file character (Ctrl+Z). The bigger catch: copy knows nothing about CSV. Every file’s header lands in the middle of your data, and a file without a final line break runs into the next file’s header. Use it only for files without headers.

PowerShell can read the files as CSV, so it writes the header once and keeps quoted values intact:

Get-ChildItem -Path exports -Filter *.csv |
  ForEach-Object { Import-Csv $_.FullName } |
  Export-Csv merged.csv -NoTypeInformation -Encoding UTF8

Two caveats. Export-Csv takes its columns from the first row it receives: in our test, a column that existed only in later files was dropped without a warning. And Import-Csv turns every row into an object, which is slow with millions of rows; collect the rows in a variable or sort them and all of them sit in memory at once. -Encoding UTF8 matters in Windows PowerShell 5.1, whose default encoding can mangle accents.

Pros: built into every Windows PC; PowerShell understands quoting and headers.

Cons: copy repeats headers; PowerShell is slow on big files and silently keeps only the first file’s columns.

Option 3: macOS and Linux command line

With identical headers, two built-in commands are enough. head writes the header of the first file, and tail -n +2 prints every file from its second line, with -q stopping it from printing file names in between:

head -n 1 exports/2026-01.csv > merged.csv
tail -n +2 -q exports/*.csv >> merged.csv

Keep the input files in their own folder so the wildcard can’t pick up merged.csv. The shell expands *.csv in alphabetical order, so name files in a way that sorts correctly: 2026-01.csv rather than jan.csv.

One trap: if a file doesn’t end with a line break, its last row and the next file’s first row end up on one line. In our test, 4,"Dan, Jr.",40 followed by 5,Eve,50 became:

4,"Dan, Jr.",405,Eve,50

awk avoids this, because it writes a line break after every line it prints:

awk 'NR == 1 || FNR > 1' exports/*.csv > merged.csv

NR counts lines across all files and FNR within the current one, so this keeps the first line of the first file and every line but the first of each file. Both versions also work on Windows in WSL or Git Bash.

Pros: very fast; nothing to install; streams files of any size.

Cons: only for identical headers; nothing checks that the columns match; a header that itself contains a line break breaks it.

Option 4: Excel Power Query

If the result fits in Excel, Power Query can combine a whole folder of CSV files in Excel for Windows:

  1. Put the files in one folder, with nothing else in it.
  2. Go to Data › Get Data › From File › From Folder, pick the folder and click Open.
  3. Click Combine › Combine & Transform Data, check the delimiter in the Combine Files window and click OK.
  4. Check the preview in the Power Query Editor, then click Close & Load.

You get one table with a Source.Name column naming each row’s file, and Refresh picks up new files. Three things to watch. A worksheet holds 1,048,576 rows, so load bigger results to the Data Model (Close & Load To… › Only Create Connection › Add this data to the Data Model). The generated query takes its column list from one sample file, so a column that only appears in other files can be silently left out. And type detection may strip leading zeros or misread dates.

Pros: point and click; refreshable; already installed with Excel for Windows.

Cons: row limit on a sheet; sample-file column trap; slow with many large files.

Option 5: Python and pandas

pandas matches columns by name, so files with different columns are combined like a union, with empty values where a file lacks a column:

import glob
import os

import pandas as pd

files = sorted(glob.glob("exports/*.csv"))
frames = []
for f in files:
    df = pd.read_csv(f, dtype=str, keep_default_na=False)
    df["source_file"] = os.path.basename(f)
    frames.append(df)
pd.concat(frames, ignore_index=True).to_csv("merged.csv", index=False)
  • Keep values as text. By default pandas guesses types: in our test, 007 became 7 and the text NA became an empty cell. dtype=str with keep_default_na=False copies values as written.
  • Read only what you need. usecols=["date", "amount"] skips the other columns, which saves memory and time.
  • Use chunks for big files. A DataFrame often needs several times the file size in memory. If every file has the same columns in the same order, append in pieces instead:
first = True
for f in files:
    chunks = pd.read_csv(f, dtype=str, keep_default_na=False, chunksize=500_000)
    for chunk in chunks:
        mode = "w" if first else "a"
        chunk.to_csv("merged.csv", mode=mode, header=first, index=False)
        first = False

Pros: free; matches columns by name; easy to add cleaning, filtering or duplicate removal.

Cons: needs Python and some code; memory hungry unless you chunk.

Option 6: csvkit csvstack

csvkit is a free set of command-line CSV tools written in Python. Its csvstack command understands quoting and writes one header:

pip install csvkit
csvstack exports/*.csv > merged.csv
csvstack --filenames -n source_file exports/*.csv > merged.csv

--filenames adds a column with each file’s name, and -n names it. With -g you choose the value for each file yourself:

csvstack -g 2025,2026 -n year sales-2025.csv sales-2026.csv > merged.csv

The group column comes first. In our test with csvkit 2.2, files with different columns were matched by name and missing values left empty.

Pros: CSV-aware one-liner; grouping column built in; easy to script.

Cons: needs Python; written in pure Python, so slow on multi-gigabyte files.

Which option should you choose?

Comparison of ways to merge CSV files
OptionDifferent columnsVery large filesInstall
MegaRows merge toolUnion or mappingYesNone (browser)
Windows copyNo, repeats headersYesBuilt in
PowerShellFirst file’s columns onlySlowBuilt in
head and tail, awkNoYesBuilt in (macOS, Linux)
Power QuerySample file’s columnsData Model onlyExcel for Windows
pandasYes, by nameWith chunksPython
csvstackYes, by nameSlowPython

Identical headers and a one-off job: awk or the merge tool. Different columns: anything that matches them by name. A monthly job: script it with pandas or csvkit.

Nine pitfalls when combining CSV files

Repeated header rows

Concatenating whole files copies every header, so a number column suddenly sorts as text or a filter shows a value called “amount”. Skip the first line of every file except the first.

Different column orders or names

Appending by position puts values under the wrong heading when one export has id,amount,name and the next id,name,amount. Match columns by name, and watch for spellings such as Order ID and order_id.

Mixed separators and decimal commas

European exports often use semicolons and write numbers as 1.234,5. Appended to a comma-separated file, their rows collapse into one column. Convert the files first, or use a tool that reads each with its own settings.

Encodings and byte-order marks

Files in UTF-8, Windows-1252 or UTF-16 can’t simply be glued together: accents turn into strings like é. An invisible byte-order mark (BOM) at the start of a file shows up as  mid-file when whole files are concatenated. Convert everything to UTF-8 first.

Files without a final line break

Many exporters leave the last line without a line break, and byte-copying tools then join it to the next file’s first row, as shown above. Use a tool that writes a line break after every row.

CRLF and LF line endings

Windows files end lines with CRLF, macOS and Linux files with LF. Mixed, some tools see a stray carriage return at the end of the last value, so amount and amount\r no longer match. Pick one line ending for the output.

Duplicate rows

Overlapping exports, such as weekly downloads that repeat the previous week’s last day, duplicate rows. Remove exact duplicates while merging (drop_duplicates() in pandas, or the option in the merge tool).

Excel’s 1,048,576-row limit

A merged file can easily outgrow Excel, which then loads the first 1,048,576 lines and leaves the rest out. Keep the result as a CSV and see our guide on opening a CSV that’s too big for Excel.

Quoted fields that contain line breaks

A comment or address can contain a line break inside quotes, so one record spans two lines. Appending is still safe, but anything that splits, sorts or filters by line can cut such a record in half.

Check the merged file

After any merge, compare the counts: the merged file should have one header plus the data rows of every input, minus any duplicates you removed. The CSV row counter counts the lines of each file in seconds without opening it. To look through the result or chart a column, open it in the plotter.

Get notified when the full viewer launches.

Scroll, sort and search millions of rows right in your browser. Leave your email and we will tell you when it is ready. No spam.

We store your email, your choices above, this page’s address and your country in our private back office, only to email you about MegaRows. See our privacy statement.

Frequently asked questions

How do I combine multiple CSV files into one?

Keep the header row of the first file and append only the data rows of the others. If the files have the same columns, a one-line awk or PowerShell command does it. If the columns differ, use a tool that matches columns by name, such as pandas, csvkit or the MegaRows merge tool, which runs in your browser.

How do I merge CSV files without Excel?

Use the command line (awk or head and tail on macOS and Linux, PowerShell on Windows), Python with pandas, csvkit’s csvstack, or a browser tool such as the MegaRows merge tool. None of them has Excel’s 1,048,576-row limit, and none of them reformats dates or strips leading zeros unless you tell it to.

How do I merge CSV files with different columns?

Match the columns by name instead of by position. pandas.concat and csvstack in csvkit 2.x do this and leave missing values empty. The MegaRows merge tool offers Union mode for the same result and Column mapping for columns whose names differ slightly, such as “Order ID” and “order_id”.

How do I stop the header row repeating when I append CSV files?

Skip the first line of every file except the first. On macOS and Linux, awk 'NR == 1 || FNR > 1' does exactly that. Windows copy and plain cat cannot skip lines, so they repeat the header; use PowerShell’s Import-Csv and Export-Csv or a CSV-aware tool instead.

Can I merge CSV files that are too big for Excel?

Yes, as long as you keep the result as a CSV. Command-line tools, pandas in chunks and the MegaRows merge tool all cope with totals of many gigabytes. Just don’t open the merged file in Excel if it has more than 1,048,576 rows, because Excel only loads the first 1,048,576 lines.

How do I add a column that shows which file each row came from?

In pandas, add it to each DataFrame before concatenating, as in the example in this guide. csvstack has --filenames, Power Query adds a Source.Name column automatically, and the MegaRows merge tool has a source_file option that is on by default in Union and Column mapping modes.

Why are two rows stuck together after merging?

One of the files did not end with a line break, so its last row and the next file’s first row landed on the same line. Tools that write a line break after every row, such as awk, pandas, csvkit and the MegaRows merge tool, avoid the problem; byte-copying tools such as copy, cat and tail do not.

Is it safe to merge confidential CSV files online?

Only if the files never leave your computer. Many online mergers upload your files to a server. The MegaRows merge tool reads and merges them locally in your browser, which you can confirm in the Network tab of your browser’s developer tools. The command line, pandas and csvkit are local too.

Send feedback

Found a bug, missing a feature or just want to say hi? We would love to hear from you.

Type
0 / 5,000

We never receive your files. Sent with your message: page /, version 0.1.0.