You have a parent product like a t-shirt, and under it sit dozens of variations: small black, small white, medium black, and so on. Each needs its own SKU, price, stock, and sometimes its own image. Get the structure slightly wrong in your CSV and you end up with orphaned variations, missing attributes, or a parent product that shows no options at all.
This guide walks through exactly how to import variable products from a CSV file, including how to lay out the spreadsheet, how variations link to their parent, and how to pull in product images from URLs. By the end you will be able to take a single CSV and end up with fully formed variable products, each with its variations, attributes, prices, stock levels, and images, live in your store.
New to importing? Start with the basic CSV import guide first, then come back here once simple products are working for you.
What makes variable products tricky
A simple product is one row in a spreadsheet: one SKU, one price, one image. A variable product is different. It is really a small family:
- One parent product that holds the name, description, and the list of possible options (sizes, colors, and so on).
- Many variations that each represent one specific combination, with their own SKU, price, and stock.
The challenge in a CSV is representing that parent-and-children relationship in flat rows. WooCommerce needs to know which rows are parents, which are variations, and which parent each variation belongs to. If that link is unclear, the import either fails or produces broken products. There are two common ways to express this in a CSV, and understanding them is most of the battle.
The CSV structure for variable products
The cleanest layout uses a parent SKU column. Every variation row points back to its parent by repeating the parent's SKU. Here is the idea:
| sku | parent_sku | name | regular_price | attribute_size | attribute_color | image |
|---|---|---|---|---|---|---|
| TEE-001 | Classic T-Shirt | 24.99 | S|M|L | Black|White | https://.../tee.jpg | |
| TEE-001-S-BLK | TEE-001 | 24.99 | S | Black | https://.../tee-s-black.jpg | |
| TEE-001-S-WHT | TEE-001 | 24.99 | S | White | https://.../tee-s-white.jpg | |
| TEE-001-M-BLK | TEE-001 | 24.99 | M | Black | https://.../tee-m-black.jpg |
A few things to notice:
- The first row is the parent. Its
parent_skuis blank because it has no parent. Its attribute columns list every possible value, separated by a pipe character (S|M|L). This is how WooCommerce knows what options the product offers. - Each following row is a variation. Its
parent_skurepeats the parent's SKU (TEE-001), which is the link. The variation's own attribute columns hold the single value for that one combination (SandBlack). - Variation rows can leave the name blank. They inherit it from the parent. This is normal and expected.
- Each row can carry its own image URL, so the parent and every variation can show a different photo.
This structure scales to any number of variations. A shirt in six sizes and five colors is one parent row plus thirty variation rows.
Preparing your images
Images are the second place imports go wrong. WooCommerce does not store the image inside your CSV. Instead, your CSV holds a URL pointing at each image, and during import the plugin downloads that image and saves it into your media library.
For this to work, every image URL needs to be:
- Publicly reachable. If the URL requires a login or sits behind a firewall, the import cannot fetch it.
- A real, working link. Open a few in your browser to confirm they load.
One detail trips up many importers: some modern image URLs have no file extension. A link from a content delivery network might end in something like /600/600 rather than /photo.jpg. Older import tools reject these because they check the URL for a .jpg or .png ending. A good importer checks the file itself rather than the URL text, so extension-less links from services like Cloudinary, Shopify, or Imgix still work. Keep this in mind if your supplier feed uses those.
Step by step: importing your variable products
Here is the full process. This uses SimpleImporter Pro, which handles the parent-and-variation grouping and image downloading for you, but the principles apply to any quality importer.
Step 1: Prepare your CSV
Lay out your file using the parent-SKU structure shown above. The essential columns for variable products are:
sku(required for every row)parent_sku(blank for parents, the parent's SKU for variations)name(on the parent; blank on variations)regular_priceand optionallysale_pricestock_quantity- One
attribute_column for each option type, such asattribute_sizeandattribute_color image(a URL)status(usuallypublish)
Save the file as CSV.
Step 2: Upload the file
In your WordPress admin, open the importer and upload your CSV. The importer reads your column headers and shows you a sample of the data so you can confirm it parsed correctly.
Step 3: Map your columns
Mapping tells the importer which column in your file corresponds to which WooCommerce field. A good importer auto-detects the obvious ones (a column called sku maps to SKU, regular_price to the regular price, and so on), so you usually only adjust a few. This is also where you confirm the variation setup: that variations are grouped by the parent_sku column, and which columns are the attributes. A live preview that shows what each row will become as a product helps you catch mistakes here, before anything is written to your store. For more on this step, see mapping columns in the docs.
Step 4: Run the import
Start the import. For large files the work runs in the background, so you can close the tab and come back. Each row is processed in order: parents are created first, then their variations are attached, and images are downloaded and assigned as the featured image.
Step 5: Check the result
Open one of your new variable products in WooCommerce. You should see:
- The parent product with its name and description.
- An Attributes tab listing your sizes and colors, marked as used for variations.
- A Variations tab with each combination, its SKU, price, stock, and image.
- The featured image, pulled from the URL in your CSV.
If everything looks right on one product, the rest of the import followed the same path.
Common problems and how to fix them
Variations imported but the parent shows no options. This usually means the parent row's attribute columns did not list the possible values, or they were not marked as the attributes used for variations during mapping. Confirm the parent row has the full pipe-separated list (S|M|L).
Some variations are missing. Check that every variation row has the correct parent_sku value, spelled exactly like the parent's SKU. A single typo breaks the link and the variation is skipped or orphaned.
No images appeared, and the media library is empty. First confirm the URLs load in a browser. If they do, the issue may be that the URLs have no file extension and your import tool rejected them, or that your server could not reach the image host. A good importer logs why each image failed so you are not guessing. On a local development environment, outbound image downloads sometimes fail due to network or certificate quirks even when the same import works fine on live hosting.
The import created duplicate products. Run imports that match on SKU. When you re-run the same file, matching rows should update the existing product instead of creating a second copy. This also lets you fix data in your spreadsheet and re-import safely. If you are seeing other failures, the troubleshooting guide covers the full list.
Cleaning up test runs: If you import a batch and decide to start over, deleting the import should also remove the products it created and the images it downloaded. Otherwise your media library slowly fills with orphaned files. Look for an importer that cleans up the images it added when you delete an import, while leaving images you uploaded yourself untouched.
Wrapping up
Variable products are not hard to import once you understand the structure: one parent row that lists the options, then one row per variation linked back by parent SKU, with image URLs the importer downloads for you. Lay the spreadsheet out that way, map the columns, preview before you commit, and check one finished product to confirm the pattern held.