Matrixify: The Field Guide to Shopify Bulk Operations at Scale
Six years of running Matrixify on production Shopify stores — export discipline, import commands, cross-store sync, dry runs, rollback files, and the failure modes nobody warns you about.
Why this post exists
Matrixify is the single most important tool in my Shopify stack, and almost nothing written about it goes past "here is how to export a CSV."
I have used it every week for years — on my own store, on an international luxury fashion brand, on a US beauty and lifestyle brand, and today on two storefronts of a US building-products manufacturer that together run an enterprise-scale catalog of 2,800+ products and 13,000+ multi-level variants. That is where you learn what Matrixify actually is: not an import app, but the write layer for a catalog that no human can maintain by hand.
This is the field guide I wish I had in year one.
What Matrixify really is
Shopify's admin is a single-record editor. Matrixify turns the entire store — products, variants, inventory, metafields, customers, orders, redirects, collections, pages, discounts — into spreadsheets you can export, diff, edit, version, and replay.
That reframing matters. Once the catalog is a file, catalog work becomes software work: you get diffs, you get review, you get rollback, you get repeatability. Without it, "update pricing on 900 SKUs" is a two-week project with a 100% chance of at least one typo reaching a customer.
The three commands that do 90% of the work
Every Matrixify import sheet can carry a Command column, and getting this wrong is how people nuke production.
UPDATE— touch existing records only. If a row does not match an existing product, it is skipped. This is the default I use for everything. It cannot create garbage.NEW— create only. Fails on collision instead of silently overwriting.REPLACE— wipe and rewrite the record. Powerful, and the reason people have bad days.
Then there are the per-field commands, and the one that matters most is Tags Command:
MERGE— append the tags in this row, leave existing tags alone.REPLACE— the row's tags become the entire tag set. Everything else is gone.
I have seen a single Tags Command: REPLACE erase merchandising tags across a whole collection because someone exported tags a week earlier and re-imported a stale column. Default to MERGE. Always. Same logic applies to Variant Command and Metafield Command.
Handle Command Tags Tags Command
redi-base-32x60 UPDATE clearance,spring-2026 MERGE
redi-base-36x60 UPDATE clearance,spring-2026 MERGE
That sheet adds two tags. Change MERGE to REPLACE and it deletes every other tag those products had.
Rule 1: the export you did yesterday is already wrong
Every change starts with a fresh export, not because the old one was wrong when you took it, but because someone else on the team, an app, or a sync job may have touched the catalog since.
The discipline: never edit yesterday's export. I keep one folder per operation:
source.xlsx— the fresh export, never modifiedchanges.xlsx— import-ready, only the rows and columns that changerollback.xlsx— current state of exactly the rows I am about to touchvalidation.csv— a script-generated diff of what should change
If the diff does not match my expectation, the import does not run. That is the whole gate.
Rule 2: export narrow, import narrower
The biggest cause of accidental damage is exporting everything and importing everything back.
If you export 91 columns and import 91 columns, you are asserting the value of 91 fields on every row — including fields you never looked at, and fields that an app owns. Import only the key column plus the columns you are changing. Matrixify ignores what is not present.
A pricing update is four columns: Handle, Variant SKU, Variant Price, Variant Compare At Price. Not ninety-one.
Rule 3: choose your key deliberately
Matrixify can match on ID, Handle, or Variant SKU. They fail differently:
- ID is exact and store-specific. It is also the one that silently corrupts: a 13-digit product ID pasted into Excel becomes
1.05E+13and every row fails or, worse, matches nothing and reports success on zero rows. Format the column as Text before you paste, every time. - Handle is stable and human-readable, but changes if someone renames a product, and a handle change is a URL change.
- Variant SKU is the best key for anything inventory-shaped, because it is the identifier your ERP, your 3PL and your retail partners already speak. Its catch: SKU maps to variants, so a product-level operation keyed by SKU needs de-duplication first — I have collapsed 90 variant SKUs down to 3 product IDs in a single migration batch.
Rule 4: Analyze before Import, every time
Matrixify's "Analyze" pass reads your file and reports what it would do, per row, without writing. Use it for:
- Any first run of a new sheet format
- Anything touching more than ~100 rows
- Anything touching price, inventory, status, or redirects
The output tells you how many rows matched. If you uploaded 340 rows and Analyze reports 338 matched, stop. Those two rows are the bug. They are usually a trailing space in a SKU, a scientific-notation ID, or a product that lives on the other store.
Then run 5 rows for real. Look at them in the admin. Then run the 340.
Rule 5: the sheet name is load-bearing
For XLSX imports, Matrixify reads the sheet name to know what object you are importing. A sheet of product statuses must be on a tab named exactly Products. Not Products (1), not Sheet1, not products.
This costs people an hour the first time and never again. Same class of gotcha: the redirects import is a two-column CSV — Redirect from,Redirect to — and it wants full absolute URLs on the destination side, per store domain.
Cross-store sync: the hardest thing Matrixify does
Running a B2C storefront and a B2B storefront on the same catalog means every catalog action happens twice, and the two stores do not share product IDs. A B2C product ID used against the B2B store returns "product not found."
What I actually do:
- Key cross-store operations on SKU, never ID. SKU is the only identifier that means the same thing in both places.
- Maintain a mapping sheet — SKU → B2C product ID → B2B product ID — regenerated from fresh exports, never hand-maintained.
- Generate both stores' files from one approved input list. I wrote a small Python generator that takes a list of parent SKUs, expands children, resolves each store's IDs separately, and emits every file for the round. It was validated by regenerating a historical batch and byte-matching the original.
- Treat out-of-sync inventory as a Sev-1. A SKU that is live on one store and drafted on the other is a support ticket and a lost order.
And the trap that is not obvious: tags are product-level data shared by every theme in the store. Importing tags to test a badge on an unpublished preview theme immediately changes smart-collection membership on the live theme. There is no theme scoping on catalog data.
Order of operations is a real thing
The clearest example: retiring an old SKU and replacing it with a new one is three operations — new product to Active, old product to Draft, old URL 301 to the new URL.
Run them in that order. Shopify ignores a URL redirect while the source URL still resolves to a live product. Draft the old product first, or your redirects silently do nothing and you find out from Search Console six weeks later.
Rule 6: keep a rollback file, and know the asymmetry
Before any non-trivial import I export the current state of the affected rows to rollback.xlsx. If something goes sideways, recovery is one import away.
But rollback is not symmetric, and this drives what I review hardest:
- A wrong product field is reversible in five minutes.
- A wrong price may have already been charged.
- A wrong redirect on a product with live ads is lost revenue and lost SEO instantly, and no rollback un-loses it.
So price and redirect files get a line-by-line before/after review with a human sign-off. Description and tag files get a spot check.
Rule 7: schedule imports, do not surprise people
- Pricing: low-traffic window, mid-week morning.
- Inventory: small deltas, hourly, automated.
- Metafield and description backfills: weekends.
- Anything touching the homepage collection or a product in an active campaign: never during the campaign.
Large jobs also queue. A 13,000-variant full import is not a thing you kick off at 4:55pm on a Friday.
Failure modes I have actually hit
- Silent zero-match success. The job completes, the report says 0 items imported, and nobody reads the report. Always open the results file.
- Scientific-notation IDs. Covered above. It is always this.
- Parent/child relationships. Activating a "mother" product can activate derived child products you did not list — separate products, separate IDs, separate URLs. Variants are not children. Missing a child leaves an orphaned live URL.
- Active but unpublished. Products flipped to Active without the Online Store sales channel added: in stock, correctly priced, and unbuyable. One audit across two stores found 164 of them, 35 carrying inventory, one with 5,469 units sitting idle. Detection is a read-only export filtered to
Status = Active, then one query foractive AND published = false, sorted by inventory. Note the limitation: thePublishedcolumn reflects the Online Store channel only — a true multi-channel audit needs the Admin APIpublicationsquery. - Images. Image rows import in order and can duplicate if you re-run a sheet that includes
Image SrcwithoutImage Command: REPLACEscoped correctly. Image work deserves its own dry run.
The part that is not about Matrixify
The tool is the easy half. What makes bulk operations safe is that every recurring job is written down: what it does, its inputs, its key column, its validation rules, its schedule, who signs off, and when it last ran with what outcome.
That document is the difference between "I import stuff sometimes" and an operations function a business can depend on. Matrixify is what makes the operations function possible; the runbook is what makes it trustworthy.
Where to start
If you have never run a bulk operation on your store, start with the least dangerous one: export your products, add SEO titles and descriptions to fifty rows, import with Command: UPDATE and only the columns you changed. Look at the results file. Then do five hundred.
The muscle you are building is not spreadsheet skill. It is the habit of never letting an unreviewed change reach a live catalog.
I have run Matrixify operations on catalogs from 600 SKUs to 13,000+ variants, across single stores and paired B2C/B2B setups. If your catalog work is still happening one product at a time, I can help — see [Matrixify expert services](/matrixify-expert), [Shopify development services](/shopify-expert), or [hire a Shopify developer](/hire-shopify-developer).
Direct: [WhatsApp +55 11 98851-2788](https://wa.me/5511988512788) · [contato.matheusabrahao@gmail.com](mailto:contato.matheusabrahao@gmail.com)
Need a senior engineer who thinks like an operator?
I take on a small number of Shopify operations and senior engineering engagements each quarter. If your store needs catalog hygiene, technical SEO, performance, or marketing automation done right — let's talk.
Continue reading
Shopify Canonical URLs: The Duplicate Content Trap in Collections and Filters
How Shopify canonical URLs actually work, why collection-scoped product URLs and filter parameters multiply your index, and the theme-level fixes that hold.
Shopify Schema Markup: What Actually Earns Rich Results Now
FAQ rich results are gone. What still earns them: the structured_data Liquid filter, Product vs ProductGroup, and the required merchant listing fields.