How Merge Excel Workbooks is built
Merge Excel Workbooks collects every worksheet from several .xlsx/.xlsm files into a single workbook. This post is about what “merge” has to mean at the cell level once two source files use the same sheet name, and what this version deliberately leaves out of scope.
Tech used
ExcelJS as both reader and writer
Unlike csv-to-xlsx, which reads CSV text and writes .xlsx, this tool’s input and output are the same format — so a single library, ExcelJS 4.4 (MIT), handles both sides: workbook.xlsx.load() to read each source file, output.xlsx.writeBuffer() to produce the merged result. Both the read and write paths are behind a dynamic import('exceljs'), keeping the ~940 KB library out of the page’s initial load.
Implementation & operational notes
Merging a worksheet means copying it cell by cell into a new workbook instance — there’s no “append this sheet” shortcut. ExcelJS doesn’t expose a way to move a worksheet object from one Workbook instance directly into another; copyCellValues() walks every row and cell of the source sheet with eachRow/eachCell and writes each value, along with its number format, into the corresponding cell of a freshly created target worksheet — plus column widths and row heights, copied separately since those live on the sheet’s structure rather than on individual cells. This is a deliberate value-level rebuild, not a byte-level copy, which is also why formatting details ExcelJS doesn’t expose through this API (some conditional formatting, embedded drawing objects) don’t make the trip — a known, stated boundary of the approach rather than an oversight.
Same-named sheets from different files are a real, expected case, not an edge case to reject. Two workbooks each having a tab named “Summary” is completely ordinary — spreadsheet templates get reused. Excel enforces worksheet-name uniqueness case-insensitively, so “Summary” and “summary” count as the same name for this purpose; createUniqueWorksheetName() checks against that same rule, and resolves a collision by appending the source file’s own name as a suffix — Summary (Q1 Report), Summary (Q2 Report) — rather than an anonymous Summary (2), so it’s still obvious after merging which original file each sheet came from.
VBA macros don’t survive the merge, and the result explicitly says so. The merged output is always a plain .xlsx, even when a source file was a macro-enabled .xlsm — ExcelJS’s writer targets the non-macro format, and macros aren’t something a value-and-formatting copy can carry across regardless. Rather than silently dropping that capability, the tool states it directly in its own copy, in keeping with this fleet’s general policy against implying a conversion is more complete than it actually is.
A minimum of two files is enforced up front, since “merge” implies more than one source. Selecting a single workbook — or none — is rejected before any parsing happens, with a specific, immediate message rather than a delayed error partway through the merge.
Try it / source
- Tool: Merge Excel Workbooks
- Source: github.com/GeppettoAndRomero/xlsx-merge