I need to perform a SKU bulk update in an existing store. I found this script: http://vagento.com/update-bulk-product-sku-using-csv-magento-2/ that works great.

The only problem is that after SKU's are updated, all product variations (for configurable product) are not linked anymore. These products are linked based on SKU, so after changing this value the Configurable Product does not contain any child products anymore.

Is there a fix for this problem? How can I preserve the child products?

  • Why do not use import?
    – KAndy
    Dec 5, 2017 at 18:28
  • You can’t update sku with import right? It will create a new product.
    – Silvan
    Dec 5, 2017 at 18:38
  • I had a quick look at the script, and on prima facie, it looks like any orders that you already have in your system will reference the OLD SKUs - which will no longer exist once you run the script - causing potential issues during Order cancellations/RMAs/etc. Also, with the SKU over-write approach - you may get into trouble, in case you ever get audited (if the whole "audit" situation applies to you i.e.) The cleaner/by-the-book approach would be to end-date/disable the OLD SKUs and setup the new SKUs as new products. P.S: I've listed out the by-the-book approach below. Dec 6, 2017 at 0:30

3 Answers 3


Try below code

First create BulkUpdate.php file on Magento2 root folder and add below code

use Magento\Framework\App\Bootstrap;
require __DIR__ . '/app/bootstrap.php';
$bootstrap = Bootstrap::create(BP, $_SERVER);
$objectManager = $bootstrap->getObjectManager();

$state = $objectManager->get('\Magento\Framework\App\State');

$fileCsv        = $objectManager->get('Magento\Framework\File\Csv');
$moduleReader   = $objectManager->get('Magento\Framework\Module\Dir\Reader');
$directoryList  = $objectManager->get('Magento\Framework\App\Filesystem\DirectoryList');
$file           = $objectManager->get('Magento\Framework\Filesystem\Io\File');

$filePath = "skus.csv"; 
if (file_exists($filePath)) {
    $rows = $fileCsv->getData($filePath);
    $count = 0;
    $successSku = [];
    $failedSku = [];
    foreach($rows as $row) {
        if($count > 0) {
            $oldSku  = (isset($row[0])) ? $row[0] : "";
            $newSku  = (isset($row[1])) ? $row[1] : "";
            if($oldSku && $newSku) {
                $productId = $objectManager->create('Magento\Catalog\Model\Product')->getIdBySku($oldSku);
                if($productId) {
                    try {
                        $productFactory = $objectManager->get('\Magento\Catalog\Model\ProductFactory');
                        $product = $productFactory->create()->load($productId);
                        $successSku[$newSku] = $newSku;
                    catch (\Exception $e) {
                        echo "Cannot retrieve products from Magento: ".$e->getMessage()."<br>"; 
                }else {
                    $failedSku[$oldSku] = $oldSku;  

After put skus.csv file on Magento2 root folder with your new sku & old sku data

CSV file format is:

enter image description here

After run BulkUpdate.php file in your browser for eg. http://magento2.com/BulkUpdate.php and check your products in admin end.

Hope all working fine.

  • Note: I received an error 'Cannot retrieve products from Magento: Invalid option value' but the update still seemed to work. This was on version 2.3.5
    – Josiah
    Jun 24, 2020 at 13:24
  • 1
    I'm surprised this hasn't been selected as solution. This works great, and keeps the links of Configurable/Simple products in place as well.
    – Jason
    Mar 21, 2021 at 11:26
  • Thank you - this saved me hours of work. I did modify the $filePath line to accept a filename as an argument ($filePath = $argv[1];) and added output under the $oldSku/$newSku assignments (echo "Old SKU: " . $oldSku . " | New SKU: " . $newSku . "\n";).
    – chazbot7
    Feb 1, 2022 at 4:37
  • This isn't working for me. The filepath ="skus.csv" line is causing the script to throw a 500 error in browser. No error thrown in any log file though. Running Nginx. Tested with a simple 'Hello World' php file that custom script definitely executing from pub folder okay.
    – zigojacko
    Mar 6, 2023 at 14:55

You can reassociate the products programatically with:

$productIds = [1, 2, ...]; // List of ids of the child products

Since you have an excel sheet mapping the new skus to the old skus it shouldn't be hard to get a list of child product ids.

You can also export your products to csv in the backend from System -> Export, the csv has a column configurable_variations that should contain a list of the old skus, you can write a script to replace those old skus with your new skus and import the products from System -> Import choosing the Add\Update import behavior.


You can achieve the desired SKU swaparoo using the following steps:

Export Current Products:

Login to Magento Admin UIX -> Navigation: System > Export > Products -> Choose "Entity Type" = Products -> Choose "Export File Format" = CSV -> Click on Continue

Perform Product Transformations:

1) Make 3 copies of the file that was downloaded. Let's call them:

* Products_Original_Backup.csv - This is something that will help us roll-back in case of a SNAFU scenario.

Original Product File - Backup

* Products_Original_ToBeEndDated.csv - This is the file you will use to end-date existing products.

Products To Be End-Dated

* Product_Updates.csv - This is the file you will make Product edits to

Product Updates

2 a) Open the Product_Updates.csv file - in a text editor - and make necessary edits to the requisite product attributes.

A few tips while performing this task:

  • Please make sure you specify the NEW SKUs in the appropriate fields corresponding to configurable/bundle/grouped products. The following files should give you a better idea on the attributes of importance - and the requisite content/formatting - for these product types:




Friendly Tip: I would recommend against using Excel, as in my experience, it tends to mess up the content/encoding of the CSV file.

2 b) Open the Products_Original_ToBeEndDated.csv file - in a text editor - and remove all columns except the SKU field. Add another header field called status and assign the value as 0

3 a) Import The Product_Updates.csv file. System > Import > Choose "Entity Type" = Products -> Choose "Import Behavior" = Add/Update -> Choose "Stop on Error" -> Click on "Select File to Import" and navigate to the location of the Product_Updates.csv file and select it -> Click on "Check Data" -> If there are no errors, Click on the "Import" button.

3 b) Import the Products_Original_ToBeEndDated.csv file. System > Import > Choose "Entity Type" = Products -> Choose "Import Behavior" = Add/Update -> Choose "Stop on Error" -> Click on "Select File to Import" and navigate to the location of the Products_Original_ToBeEndDated.csv file and select it -> Click on "Check Data" -> If there are no errors, Click on the "Import" button.

Trust, But Verify!

At this point, you'll need to verify two things (primarily): (a) The OLD SKUs should've been disabled. (b) The NEW SKUs should be active.

Some of the important Places/Flows to check:

  • Product Catalogs
  • Product Details Page
  • Order 2 Cash flow
  • Searches
  • Checkout
  • Historical Orders
  • Returns Flows

Before File Import BEFORE File Import

AFTER Product Update CSV File Import After Product Update CSV File Import

AFTER Disable Old Products CSV Import enter image description here

Note: In case something goes awry - you can always rollback by reimporting the Products_Original_Backup.csv file.

P.P.S: You will also need to end-date/disable/delete the new SKUs. You can do this via the CSV approach outline in 2b or directly from the Admin UIX.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.