← Back to blog

Magento 2 Product Import: CSV Best Practices That Avoid Data Loss

Rodrigo Biazzi

The native product import in Magento is fast and handles most catalog updates well, as long as you know how it treats empty cells, store views and behaviors. Most import disasters I have been asked to clean up came from one of those three. This article is a set of rules I follow for imports on Magento Open Source and Adobe Commerce 2.4.8, through the admin at System, Data Transfer, Import, or through code that uses the same import model.

Start from an export

Never build an import file from scratch from the documentation. Export a few products of each type from the same store, open the file and use it as the template. The export shows the exact column names, the separator for multi select values, how additional_attributes is formatted, and how configurable variations are written. It also shows store view rows if you export with them.

Keep the file in UTF-8 without a byte order mark, and open it with a tool that does not reformat SKUs. Spreadsheet programs like to turn long numeric SKUs into scientific notation and strip leading zeros. A SKU that changes on the way in creates a new product instead of updating the existing one.

Choose the behavior carefully

BehaviorWhat it doesWhen to use it
Add/UpdateCreates new SKUs and updates the columns present for existing onesAlmost always
ReplaceDeletes the existing products with those SKUs and creates them againRarely, with a backup
DeleteDeletes the products with those SKUsBulk removal

Replace deserves a warning. Because the products are deleted and recreated, they get new entity IDs. Anything linked to the old ID is affected: URL rewrites, reviews, wishlist items, links from other systems that stored the ID. Use Add/Update unless you have a specific reason not to.

Send only the columns you mean to change

With Add/Update, Magento only touches the columns present in the file. A file with sku and price changes only the price. That is the safest way to do bulk updates. Large files with every column exported and re-imported risk writing back stale values that someone changed in the admin in the meantime.

sku,price,special_price
ABC-001,49.90,
ABC-002,59.90,44.90

Empty cells do not clear values

In the example above, the empty special_price for ABC-001 does not remove an existing special price. Empty cells are ignored. To clear a value on purpose, use the constant __EMPTY__VALUE__, which Magento recognizes during import:

sku,special_price
ABC-001,__EMPTY__VALUE__

This one rule explains a lot of "the import did not work" reports. The import worked, it just did not do what people expected from an empty cell.

Store view rows

Values per store view, such as translated names or descriptions, go in extra rows with the same SKU and the store_view_code column filled in. The first row for a SKU, with an empty store view code, holds the default values. Rows for store views should contain only the columns that differ, otherwise you create store view overrides for every attribute, and later changes on the default scope no longer show on that store view.

sku,store_view_code,name,description
ABC-001,,Blue cotton shirt,Default description
ABC-001,pt_br,Camisa azul de algodao,Descricao em portugues

Unwanted store view values are one of the most common catalog problems I see on older stores. If you find them, they can be removed from the EAV tables by store ID, after a backup and on staging first.

Attribute values

  • Dropdown and multi select options must exist. The core import does not create new options. A value that does not match an existing option label fails validation for that row. Create the options first, with a data patch or through the admin.
  • Custom attributes can be separate columns or go in additional_attributes as code=value pairs separated by commas. Separate columns are easier to read and to diff.
  • Attribute set and product type are required for new products. For existing products they can be left out.
  • URL keys must be unique per store. When a URL key collides with another product or a category, the row fails with a URL key error. Fix the data instead of generating random suffixes, because those URLs end up in search engines.

Images

The base_image, small_image, thumbnail_image and additional_images columns take file names relative to the images directory set in the import form. By default that is pub/media/import. URLs also work, but Magento downloads each one during the import, which is slow and fails silently on broken links. For large imports, copy the files to the server first and reference them by relative path.

Importing images again for products that already have them adds new copies to the gallery. Only include image columns when the images actually change. More about the storage and resize side in product images optimization.

Configurable products

Import the simple children first, or place them earlier in the same file. The configurable row then links them through configurable_variations, with each child as sku=...,attribute=value and children separated by a pipe:

sku,product_type,configurable_variations
SHIRT,configurable,"sku=SHIRT-S,size=S|sku=SHIRT-M,size=M|sku=SHIRT-L,size=L"

The children must have the configurable attribute values set, and the attribute must be global scope with a dropdown or swatch input. Check the export of an existing configurable for the exact format your version writes, including the configurable_variation_labels column.

Validation and errors

Always click Check Data before Import, and read the errors. The validation strategy decides what happens when rows fail. Stop on Error aborts the whole import, Skip error entries imports the valid rows and skips the rest, up to the allowed error count. For production I prefer Stop on Error with a small file I already validated on staging. Skipping rows silently is how half updated catalogs happen.

Magento keeps a history of imports with the file and the error report under System, Data Transfer, Import History. Keep those files when something goes wrong, they show exactly what was sent.

Large files

  • Split them. Files with tens of thousands of rows can hit PHP time and memory limits in the admin. Split into chunks of a few thousand rows and import them in sequence.
  • Indexers on schedule. With Update on Save, the import triggers reindexing as it goes. On schedule, the changes are picked up by cron afterwards. See indexer modes: save vs schedule.
  • Use the CLI or code for recurring imports. The admin form is fine for occasional work. For daily feeds from an ERP, a cron job that calls the import model, or a library built on it such as FireGento FastSimpleImport, is more reliable. The integration side is covered in ERP integration patterns.

Adobe Commerce adds scheduled import and export jobs in the admin, which can pull files from a remote location on a schedule. That feature is not in Magento Open Source.

A checklist before every import

  1. Database backup, or at least a dump of the catalog tables.
  2. Run the same file on staging with a recent copy of production data.
  3. Only the columns that need to change, with the SKU column exactly as stored.
  4. Dropdown options and attribute sets created beforehand.
  5. Check Data with no errors, or errors you understand.
  6. Import outside peak hours, then confirm indexers and cron caught up.
  7. Spot check a few products on the storefront and in the admin, including a store view.

FAQ

How do I clear an attribute value with a Magento import?

Put __EMPTY__VALUE__ in the cell. An empty cell is ignored with Add/Update and keeps the existing value.

Why does my import create duplicate products?

The SKU in the file does not match the stored SKU exactly. Spreadsheet tools that change number formats, stripped leading zeros and stray spaces are the usual causes.

Does the Magento import create attribute options automatically?

No. The core import expects dropdown and multi select values to exist already. Create them before importing, or the rows fail validation.

Is Replace behavior safe to use?

It deletes and recreates products, so they get new IDs and lose data linked to the old ones. Use Add/Update for updates and keep Replace for rare cases with a backup.

I am available for freelance Magento and Adobe Commerce work, including catalog imports and data migrations. If you need help with this, get in touch.

Related articles