How to merge shopify csv exports
- Step 1Identify your export scenario — Shopify exports get split in three documented ways: (1) 15 MB per-file cap — sellers batch by filter (Vendor, Type, Date range) and export each batch separately; (2) >100 variants on a single product — Shopify emails a multi-file ZIP rather than direct-download; (3) multi-month archives — sellers download month-by-month and concatenate for annual analysis. All three scenarios produce same-schema files that merge cleanly with header-matching.
- Step 2Export the CSV batches from Shopify admin — Products: Catalog → Products → filter → Export →
Plain CSV file→Current pageorAll matching→ wait for the file (or email link if >100 variants). Customers: Customers → Filter → Export. Orders: Orders → Filter → Export → chooseExport orders(notExport transaction histories— those are a different schema). Make sure every batch comes from the same export type — products and orders have different schemas and shouldn't be merged together. - Step 3Drop all the CSV files onto the merger above — Free tier allows 2 files; Pro removes the limit. Files are processed in the order you add them — the output keeps the first file's row order followed by each subsequent file's rows in turn. Store data, customer PII, and order amounts never reach a server.
- Step 4Pick strict vs union mode — Strict: requires every file to have the same header set. Rejects the merge with an error if any file has extra or missing columns — surfaces accidental Products+Orders mixing immediately. Union (default): takes the union of all headers across files; rows from a file missing some columns get empty cells in those positions. Use union when you've made schema changes (added custom fields, enabled metafields) between export dates and need to merge old + new exports. For same-store same-export-type same-day exports, strict is always the right choice.
- Step 5Review the merged preview before downloading — The output panel shows: total rows in (per file + sum), output row count, and the unified header row. Cross-check the total against your expected count — for Products, the count should match the sum of each batch's
Handlecount (variants share Handle so total rows ≠ total products). For Orders, the count should match the sum of orders × line items per order. - Step 6Use the merged file downstream — For analysis (BI, accounting, year-end reports): the merged CSV is ready as-is. For re-importing to Shopify (rare but valid for migrations): fork the clean-shopify-csv-workflow which adds the cleaner + duplicate-finder steps that catch variant-pattern issues and
_small/_thumbimage URL problems before the import.
What this looks like in Shopify
Reference screenshots from Shopify's own help documentation, shown here to ground each cleaning step in the UI you actually see. Each image links back to its source page.

Handle. Only the first row has full product data; subsequent rows are variant-only. csv-merger concatenates these verbatim. Never run a Handle-keyed dedupe on the merged output — that would destroy variants. See variant-pattern preservation below.Source: help.shopify.com
Shopify export scenarios that need merging
The documented Shopify behaviours that produce multiple CSVs you'll want to merge. Verified against Shopify's official help docs as of May 2026.
| Scenario | Trigger | Files produced | Merge mode |
|---|---|---|---|
| 15 MB per-file cap reached | Catalog / customer list / order history exceeds Shopify's documented per-file limit | Multiple CSVs from the same export type, batched by user-chosen filter (Vendor / Type / Date range) | Strict — same schema across all batches |
| Product with >100 variants | Single product has more than 100 variants — Shopify emails the export as a multi-file ZIP rather than direct download | Multi-file .zip containing 2–4 CSVs | Strict — same schema, just split because of variant count |
Export timeout (There was an error exporting your products. Try again in a few minutes) | Shopify's documented error wording when an export of thousands of variants times out at the server | User filters down and exports the smaller subsets one at a time | Strict |
| Annual / monthly archive concatenation | Seller exports orders / transactions month-by-month for compliance archive, year-end report, or accountant handoff | 12 monthly CSVs that need stitching into a single yearly file | Strict (if schema unchanged) or union (if Shopify added a column mid-year) |
| Pre-migration platform snapshot | Seller is migrating to another platform; exports Products + Customers + Orders separately, then merges by entity type | One CSV per entity type — keep separate per type, merge only within type (don't mix Products with Customers) | Strict per entity type |
| Filtered-by-Vendor batched exports | Operations team splits supplier-side audits by Vendor filter — one batched export per supplier for review | One CSV per Vendor — concatenate after audit | Strict |
Strict vs union mode — when to use which
csv-merger has two header-matching modes. The trade-off is data-safety (strict) vs flexibility (union).
| Mode | Behaviour on mismatched headers | Use when | Risk |
|---|---|---|---|
| Strict | Rejects the entire merge with an error if any file has columns the others don't | Same store + same export type + same export date → exports always share schema | None for the use case — strict surfaces accidental misuse (mixing Products with Orders) immediately |
| Union (default) | Takes the union of all headers; missing columns in a file become empty cells in those positions for that file's rows | Schema changed between exports (custom field added, metafield enabled, new Shopify-side feature column appeared mid-year) | Empty cells can be mistaken for 'no value' when the actual meaning is 'this field didn't exist for this row's source file' — note the provenance in a separate source_export_date column if it matters |
Variant-pattern preservation
Shopify products are not flat — variants are encoded as additional rows sharing the parent's Handle. The merger does NOT dedupe or alter these rows. Awareness of the pattern prevents downstream tools from corrupting it.
| Pattern | What it looks like | Merger behaviour |
|---|---|---|
| Single-variant product | One row with full data: Handle, Title, Body (HTML), Vendor, options, etc. | Concatenated unchanged |
| Multi-variant product (e.g. T-shirt with sizes S/M/L) | First row has full data + first variant; subsequent rows share the Handle but leave Title/Body (HTML)/Vendor blank — only the variant columns (Option1 Value, Variant SKU, Variant Price, Variant Image) are populated | All rows concatenated unchanged. Do NOT dedupe on Handle after merging — that would destroy variants |
| Same Handle across two different products in two batches | Genuine cross-product conflict — this should never happen in practice (Handles are unique per store) but can occur if you accidentally merged exports from two different Shopify stores | Merger doesn't detect this — same Handle from two stores merges as if it were one product with extra variant rows. Use csv-duplicate-finder on the Handle column after merging to surface duplicates for manual review |
Cookbook
Real Shopify export scenarios with the corresponding merger configuration.
Batched product export by Vendor
ExampleOperations team has 8 suppliers each generating their own audit CSV via the Vendor filter. All exports share the standard Shopify Products schema — strict mode catches any accidental schema drift.
Inputs (all from Catalog → Products → Vendor filter → Export): acme-products-2026-05-15.csv (1,200 rows) bestbrand-products-2026-05-15.csv (980 rows) ... 6 more files Config: mode: strict Output: all-suppliers-merged.csv (~9,500 rows) Headers identical across all files; variant rows preserved; same Handle within a file = variant; same Handle across files = genuine cross-Vendor conflict (run csv-duplicate- finder on Handle column to surface for review).
Monthly orders concatenated to an annual archive
ExampleYear-end accounting handoff: 12 monthly Orders exports → 1 annual file. Same Shopify store + same export type = schema is stable. Strict mode.
Inputs: orders-2025-01.csv orders-2025-02.csv ... orders-2025-12.csv Config: mode: strict Output: orders-2025-annual.csv Concatenated in file order (Jan first, Dec last). Multi-line orders preserved — orders with N items appear as N rows with subsequent rows leaving non-item fields blank, same as in the source files.
Schema-drifted exports between Q1 and Q4 (union mode)
ExampleShopify added a new metafield column to Products mid-year. Q1 export has 32 columns; Q4 export has 33. Strict mode rejects the merge. Union mode produces a 33-column output where Q1 rows have empty cells in the new column.
Inputs: products-q1-2026.csv (32 columns) products-q4-2026.csv (33 columns — one new metafield) Strict mode: error — header mismatch Union mode: succeeds → 33 columns; Q1 rows have empty cell in the new column. Recommendation: add a 'source_export_date' column manually to each file before merging so empty cells in the new column are interpretable as 'field didn't exist yet' vs 'no value'.
Concatenating the 4-file ZIP Shopify emails for >100-variant products
ExampleA single product with 150 variants triggers Shopify's emailed multi-file ZIP. Extract the ZIP, drop all 4 CSVs onto the merger.
Inputs (extracted from Shopify's emailed .zip):
products_export_1.csv (~50 rows — the high-variant product
plus other products in the batch)
products_export_2.csv
products_export_3.csv
products_export_4.csv
Config: mode: strict (Shopify guarantees identical schemas)
Output: single merged CSV ready for re-import / analysis.Combining Products + Customers (don't — they're different schemas)
ExampleThis is the anti-pattern strict mode catches. Products export has columns like Handle, Title, Vendor, Variant Price. Customers export has First Name, Last Name, Email, Total Spent. The two should NEVER merge — they're different entity types.
Attempt: products.csv (Handle, Title, Vendor, ...) customers.csv (First Name, Email, Total Spent, ...) Strict mode: error — header mismatch (the merger refuses to silently merge incompatible schemas) Union mode: succeeds but produces nonsense — a 50-column mess with each row populated for either Products columns or Customers columns but not both. Useless downstream. Fix: keep Products and Customers as separate merged files, one per entity type.
Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
`There was an error exporting your products. Try again in a few minutes.`
Shopify export timeoutShopify's documented error wording for product exports that contain too many variants to generate in the standard timeout window. Fix per Shopify's docs: 'split your export into multiple smaller files by filtering your products in the Shopify admin before exporting'. The merger then combines the batches back into one file.
15 MB per-file limit reached
Shopify documented capShopify documents a 15 MB per-file limit for product, inventory, and customer CSV exports. Larger catalogs must be batched at export time. Same applies on the import side — if your merged file exceeds 15 MB and you intend to re-import, split with csv-row-splitter before upload.
Single product with >100 variants emails a multi-file ZIP
Shopify documented behaviourQuoted from Shopify's docs: 'If any single product has more than 100 variants, then the CSV file is emailed to you.' The emailed file is a multi-file ZIP containing 2–4 CSVs that share the same Products schema. Extract the ZIP, drop all the CSVs onto the merger in strict mode.
Variant rows survive the merge (correctly)
By designShopify products with multiple variants produce multiple rows in the export, all sharing the same Handle. The first row carries Title, Body (HTML), Vendor, etc.; subsequent rows leave those blank and only populate variant-specific columns. The merger does NOT alter this — variant rows are preserved verbatim. Critical: don't run a Handle-keyed dedupe after merging or you'll destroy variants. The clean-shopify-csv-workflow handles this correctly by using csv-duplicate-finder (which marks but doesn't delete) instead of csv-deduplicator.
Mixing Products + Customers exports
Strict mode rejects; union mode produces garbageProducts and Customers have completely different schemas. Strict mode catches the mistake immediately. Union mode would succeed but produce a 50-column file with each row populated for only one entity type — useless. Keep export types in separate merged files.
Order exports vs Transaction History exports
Two different CSV schemasShopify's Orders page has two export buttons: Export orders (the order-line-item view) and Export transaction histories (per-transaction financial view). These produce different CSVs with different schemas. The merger's strict mode catches the difference; don't try to merge them together — keep one merged Orders file and one merged Transaction file.
Schema drift between export dates
Union mode requiredShopify occasionally adds new columns to standard exports as new features ship (metafields, new lifecycle stages, etc.). A Q1 export and a Q4 export from the same store may have a 1-column difference. Strict mode rejects; union mode produces a unified file with empty cells in the new column for older-batch rows. Add a source_export_date column to each input file before merging so the empty cells can be interpreted as 'field didn't exist yet'.
Same Handle appears across two different Shopify stores
Genuine cross-store conflictIf you accidentally merge exports from two different Shopify stores (e.g. a UK store and a US store with overlapping product catalogues), the same Handle from each store will merge as if it were one product with extra variant rows — silently corrupting both products' data. The merger doesn't detect cross-store mixing. Run csv-duplicate-finder on the Handle column after merging to surface duplicates for manual review.
Frequently asked questions
Why do I have multiple Shopify CSV exports to merge in the first place?
Three documented Shopify scenarios. (1) 15 MB file cap: Shopify caps each export file at 15 MB. Larger catalogs / customer lists / order histories must be batched at export time by filtering on a subset (Vendor, Type, Date range, etc.). (2) >100 variants on a single product: Shopify emails a multi-file ZIP rather than direct-downloading. (3) Export timeout: thousands of variants in one product can hit the documented 'There was an error exporting your products. Try again in a few minutes' error — fix is to filter and export in smaller batches. All three produce same-schema files that the merger combines cleanly.
Will merging destroy my Shopify product variants?
No — the merger does NOT dedupe. Variant rows (multiple rows sharing the same Handle where only the first has full product fields) are concatenated verbatim, preserving the variant structure. However: don't run a Handle-keyed dedupe step after merging. That would treat every variant row as a 'duplicate' of the parent and delete variants. Use csv-duplicate-finder (which marks but doesn't delete) if you need to surface duplicates for review, or fork the clean-shopify-csv-workflow which handles this correctly.
Strict vs union mode — which one should I pick?
Strict is right for almost every Shopify-merge case. Same store + same export type + exports from the same day all share schema. Strict surfaces accidental mistakes (mixing Products with Orders, mixing a current export with an older one that's missing a recently-added column) immediately. Union is for the deliberate cross-time-range case: you know Shopify added a column between Q1 and Q4 and you want one file with all data, accepting empty cells where the column didn't yet exist. Add a source_export_date column to each input file before union-merging so future-you can interpret the empty cells.
Can I merge a Products CSV with a Customers CSV?
No, and you shouldn't try. Products and Customers have completely different schemas (Handle, Title, Vendor vs First Name, Email, Total Spent). Strict mode rejects this merge; union mode would produce a useless 50-column file. Merge within entity type only — one merged Products file, one merged Customers file, one merged Orders file. If you need to relate them, use Shopify's Customer ID field which appears in both the Orders and Customers exports.
What about merging Orders exports with Transaction History exports?
Same answer — different schemas. Shopify's Orders page has two distinct export buttons: Export orders (one row per order line item) and Export transaction histories (one row per payment / refund / partial-capture transaction). The two have overlapping but distinct columns. Keep them as separate merged files. If you need to relate them, both share the Name field (the #1001 order number).
Will the merged file re-import to Shopify cleanly?
Only if your merged file stays under Shopify's 15 MB import limit (same cap as exports) AND you haven't introduced any of the standard Shopify-import gotchas. The merger doesn't validate import-readiness — it just concatenates. For re-import use, follow the merge with the clean-shopify-csv-workflow, which adds the cleaner (variant-aware) + duplicate-finder (Handle conflicts) + image-URL validation steps before the import.
What's the largest set of Shopify CSVs I can merge?
Free tier caps the merger at 2 files; Pro removes the file-count limit. The browser-memory ceiling is ~5–10M rows on desktop Chrome. The downstream constraint is the import side: Shopify caps at 15 MB per upload, so merging 20 monthly orders files into a 200 MB year archive is fine for analysis but you'd need to re-split before re-importing (use csv-row-splitter).
Does the merger handle the multi-file ZIP Shopify emails for >100-variant products?
Yes — extract the ZIP, drop all the CSVs onto the merger in strict mode. Shopify guarantees the schemas are identical across the split files (they're literally the same export, just chunked because of the variant count). The merger produces one re-importable file (subject to the 15 MB import cap if you intend to re-import).
Will my Shopify store data be uploaded to JAD Apps?
No. PapaParse runs entirely in your browser. Product titles, customer PII, order amounts, variant SKUs — none of it reaches a server. The only thing saved server-side is a single counter (files merged, no content) for signed-in dashboard stats. You can opt out in account settings.
Can I run this in an automated pipeline?
Yes — GET /api/v1/tools/csv-merger returns the option schema; pair the @jadapps/runner once and POST the payload to 127.0.0.1:9789/v1/tools/csv-merger/run. Common pipeline: monthly Shopify Orders export → runner-side merge into an annual archive → push to S3 / Drive for accountant. Store data never reaches JAD's servers.
What if my Shopify catalog has columns I added via metafields?
Metafields appear as additional columns in the standard Products export when they're configured as 'exportable' in the metafield definition. All exports from the same store at the same point in time include the same set of metafield columns — strict mode handles them like any other column. If you added a metafield between two export dates, use union mode to merge old + new (and consider adding source_export_date for provenance).
Can I merge files from different Shopify stores?
Technically yes — same export type produces the same schema regardless of which store it came from. Practically risky: Handle values may overlap across stores (e.g. a t-shirt-blue Handle exists in both stores as different products). The merger doesn't detect this; run csv-duplicate-finder on the Handle column after merging to surface cross-store conflicts before any downstream processing. Better practice: add a source_store column to each input file before merging so downstream tools can filter by origin.
Privacy first
Processing runs locally in your browser with PapaParse. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.