Twelve monthly exports. Or one file per branch, per client, per campaign. The report wants a single table, and the obvious approach — open them all, copy, paste, repeat — works exactly until the day one of the files has its columns in a different order and nobody notices for a quarter.
Merging CSV files is not hard. It is just unusually easy to do in a way that produces a file which looks right and is not. This page is about the specific ways that happens and how to rule each one out.
Every CSV carries its column names on the first line. If you concatenate files line by line — with copy *.csv all.csv on Windows, or cat *.csv > all.csv on macOS and Linux — you get one header at the top, which is correct, and then one more header buried in the middle of the data for every additional file, which is not.
Those stray rows are not harmless. A column of amounts that now contains the literal text Amount somewhere in the middle stops being a numeric column: sums silently skip it, sorting puts it somewhere strange, and any tool that infers types from the column will infer "text" and treat every number as a string.
The one-liner that does it correctly — header from the first file only, data from all of them:
PowerShell: Get-ChildItem *.csv | Import-Csv | Export-Csv all.csv -NoTypeInformation -Encoding utf8
macOS / Linux: head -1 first.csv > all.csv && tail -q -n +2 *.csv >> all.csv
The PowerShell version also matches columns by name rather than by position, which is the second problem. The shell version does not — it is line-based, so it is only safe when every file has identical columns in identical order.
This is the one that costs money. Two exports from the same system, generated three months apart, can carry the same columns in a different order — someone added a field, a report template was edited, a vendor changed an API. Concatenate them by line and every value after the divergence point lands in the wrong column. Dates appear in the amount column, amounts in the reference column, and the file still parses perfectly, because a CSV has no idea what its columns are supposed to mean.
The fix is to merge by header name: read each file's first line, align the names, and write a single output whose columns are the union of all of them. Where a file does not have a column, the cell is left blank rather than shifting everything left.
Files get missed. A glob pattern does not match a file named with a space, one file is still open in Excel and locked, one is in a subfolder. The merged file appears, looks plausible, and is missing a month.
Always reconcile the row count. Sum the source files' line counts, subtract one per file for the headers, and compare with the merged file's count minus one.
Windows: (Get-Content file.csv | Measure-Object -Line).Lines
macOS / Linux: wc -l *.csv
If the two numbers do not match, stop. A merge you cannot reconcile is not a merge, it is a guess.
| Method | Matches columns by | Best when |
|---|---|---|
| Copy and paste in Excel | Whatever you paste — by eye | Two or three small files, once |
copy / cat | Position | Never, unless you have verified every file's header is byte-identical |
PowerShell Import-Csv | Name | You are comfortable in a terminal and want it scriptable |
| Excel Power Query (From Folder) | Name | The same folder refills every month and you want a refresh button |
| A browser merge tool | Name | One-off, files you would rather not upload anywhere |
Merge CSV files takes several files at once, reads each one's header, aligns the columns by name, and writes a single table. Files with extra columns contribute them; files missing a column get a blank rather than a shift. It runs entirely on your own machine — the files are read by the page, not sent to a server, which matters when the files belong to a client rather than to you.
If you want to confirm that rather than take it on trust, open your browser's developer tools, switch to the Network tab, and drop the files in. The page loads its own code and then makes no further requests. That is the whole verification, and it takes ten seconds. There is more on why that is possible at all in how to analyze a CSV without uploading it.
A combined file has two predictable problems that the individual files did not.
Duplicates. Overlapping date ranges are the usual cause — the March export ran on the 1st of April and the April export starts on the 31st of March. Every row in the overlap now exists twice, and every total is wrong by that amount. Remove duplicate rows deals with it, and how to find duplicates in a spreadsheet covers the harder question of what counts as a duplicate in the first place.
Size. Twelve files of 150,000 rows make a file Excel cannot fully open. If the merged result is over 1,048,576 rows, Excel loads part of it and warns you once — see opening a CSV that is too big for Excel.
Each is a single page with no account and no server behind it.
Keep one header, not one per file. Match columns by name, never by position, because two exports from the same system are not guaranteed to have the same column order. Count the rows before and after and make the numbers agree. Then check for duplicates in the overlapping periods, because a merge is the most reliable way there is to create them.
How to find duplicates in a spreadsheet: what a duplicate actually is when only some columns match.
How to open a CSV that is too big for Excel: what to do when the merged file passes 1,048,576 rows.
Why Excel ruins CSV files: the conversions that damage a file the moment it is opened.
Sheet Insights reads an Excel or CSV file in your browser and builds the analysis straight away — totals by category, trends over time, column statistics, outliers, data-quality checks and a repeatable clean-up recipe for the columns that always come in dirty. No row limit, no account, no upload. The free version opens two files of your own and shows all of it; saving the cleaned file, the report or the JSON back out is what the Windows app does.
Open it and drop a file in