The CSV importer does exactly what the file tells it, which is the problem. How variations, SKUs, images and timeouts behave, and how to make an import you can safely run twice.
By Rehan Idrisi · · 7 min read
Part of: WooCommerce
An import that runs clean across ten test rows can still wreck a catalog at four thousand. Nothing about the mechanism changes between the two. What changes is that real supplier data contains duplicate SKUs, dead image URLs, half-specified variations and three spellings of the same category, and the importer has a defined behaviour for every one of those situations that is not always the behaviour you would have chosen.
WooCommerce's CSV importer reads a flat file where one line is one product record, and a type column decides what kind of record it is. A simple product is self-contained: one row, one SKU, one price. A variable product is a parent row that declares which attributes vary, and carries no price of its own. Each variation is then a separate row with its own SKU and price, pointing back at the parent by the parent's SKU. Get that reference wrong and the variations arrive as orphans or fail outright, leaving a product on the shop that nobody can buy.
Type,SKU,Name,Parent,Regular price,Attribute 1 name,Attribute 1 value(s)
variable,TSHIRT,Cotton T-Shirt,,,Size,"S, M, L"
variation,TSHIRT-S,,TSHIRT,499,Size,S
variation,TSHIRT-M,,TSHIRT,499,Size,M
variation,TSHIRT-L,,TSHIRT,549,Size,LThe parent has to list every value its variations use. A variation carrying a size the parent never declared has nothing to attach to.
WooCommerce enforces one SKU per product across the whole catalog, variations included. A row carrying a SKU that already exists gets refused on a fresh insert and reported as a failed row, instead of quietly creating a second copy. That behaviour is the one you want. Trouble starts with blank SKUs, or with the same SKU appearing twice because a supplier sheet listed a product under two names. Blank leaves the importer nothing to match on, so a second run inserts duplicates instead of updating what is already there. Every downstream system you will ever connect, from marketplace feeds to accounting to stock sync, keys on SKU as well. Deduplicate before the import, never after.
Run the same file twice without the update option enabled and every existing row errors. Enable it and the importer matches on ID first, then SKU, and overwrites the columns the file contains. The columns it does not contain are where people get caught. A file that omits a column leaves the stored value alone, so a two-column file of SKU and price is a safe way to reprice a catalog. A full supplier export with an empty description column is a different story, and can blank descriptions somebody spent a week writing. Read your own file column by column before pointing it at live products.
The images column takes URLs separated by commas, the first becoming the featured image and the rest the gallery. Your server downloads each of those files in turn and writes them into the media library. Two things follow from that. Import time is bound by how quickly the other server responds, so a slow image host can stretch a small catalog into hours. And a URL that 404s raises an error against its row, so an import that looked finished can leave products with no image, or rows that never landed at all. Run a plain status check over the image URLs first. Finding out halfway through a long import costs far more than checking does.
Any category path in the file that does not exist yet gets created during the import. Attribute values work the same way. This is convenient, and it is also how a catalog ends up with Mens, Men's and Men s sitting side by side, because three supplier files spelled it three ways. Nothing warns you. A typo deep in a hierarchy path silently builds a whole new branch. Normalise category and attribute spellings in the spreadsheet, where find and replace takes seconds, because unpicking them later means reassigning products by hand.
The importer works through the file in batches across repeated background requests, so no single request has to process everything. Each batch still has to finish inside PHP's execution time and memory limits, and image downloads make the cost of a row unpredictable. A batch that exceeds either limit returns a server error and the run stops where it stopped. Rows before that point are in the database. Rows after it are not. Recovery means a smaller batch size and a re-run with updating enabled, which is painless only if the SKUs are clean, since SKU is what the re-run matches on.
This site has an in-browser Product CSV Validator that checks a product CSV's structure and the common import errors before you upload it anywhere, and it runs entirely on your device, so a supplier's price list never leaves the machine. The SKU Generator helps when a file arrives with no SKUs at all and you need a consistent scheme across it. CSV to JSON and Line to CSV are useful for the earlier stage, when the data turns up in a shape no importer will accept.
Duplicate or missing SKUs. WooCommerce matches existing products by SKU when updating, so blank SKUs make a re-run insert copies instead of updating, and duplicates fail rows outright. Clean the SKU column and validate the file structure before uploading, because repairing a corrupted catalog afterwards is manual work.
Check a product CSV for missing columns, broken variant handles, duplicate SKUs, invalid barcodes and bad prices before you import it.
Generate consistent SKU codes in bulk from a custom pattern with variant permutations, sequential numbering and collision checking.
Turn a CSV or TSV table into JSON records, or flatten JSON back into a spreadsheet-ready table.
Convert a column of lines into a comma separated list, or split a delimited list back into one item per line.