Update Shopify Inventory from CSV Files On Your FTP Server

13 min setup
No coding required
Runs automatically

Keep your Shopify inventory up-to-date with automated updates from a CSV on your FTP server. This MESA workflow pulls SKUs and stock levels directly from the file and syncs them in real time. Customize the schedule to fit your needs, reducing manual effort and errors while keeping your store stocked.

ftp icon
Fetch CSV file from server
Loop over rows in CSV file
Get inventory Item ID for each item
Shopify logo icon
Set the new inventory level

You're in good company

"MESA has been a game changer for us. And, if you ever get stuck, their support team is always super helpful."

  • Ico star
  • Ico star
  • Ico star
  • Ico star
  • Ico star
PetFriendly

"It's like Zapier but exactly designed for Shopify. I have been able to complete all the workflows that I've needed."

  • Ico star
  • Ico star
  • Ico star
  • Ico star
  • Ico star
Zailys

"The MESA team has been amazing at helping us set up our automations. We would highly recommend this app!"

  • Ico star
  • Ico star
  • Ico star
  • Ico star
  • Ico star
Rothy's

How it works

4 steps to start automatically updating Shopify inventory from CSV files on your FTP server

ftp icon

Fetch CSV file from server

App connector: FTP • Time to complete: 8 minutes
Why this matters: This trigger connects to your FTP server on schedule to retrieve inventory data files, enabling automated sync between your warehouse management system or ERP and Shopify without manual CSV uploads.

This scheduled trigger connects to your FTP server hourly and fetches a CSV file that you specify. You need to configure several settings during setup:

(1) FTP credentials—configure your FTP server connection details in MESA's FTP integration settings,
(2) File path—enter the path to your CSV file (you can use wildcards like "inventory/Stock.csv" to match multiple files),
(3) CSV format requirements—your CSV must include columns named "SKU" and "Inventory" (case-sensitive), and
(4) Schedule—adjust the frequency if hourly is too often or not frequent enough for your needs.

The CSV data is parsed into an array where each row becomes an object accessible as {{ftp}} with properties like {{ftp.SKU}} and {{ftp.Inventory}}.

Loop over rows in CSV file

App connector: Loop • Time to complete: 0 minutes (Auto-configured)
Why this matters: Processes each product in the CSV individually, ensuring every SKU gets its inventory updated even if the file contains hundreds or thousands of products.

This loop step iterates through each row in the CSV file stored in {{ftp}}. For every row, the loop executes the subsequent SKU lookup and inventory update steps using {{loop.SKU}} and {{loop.Inventory}} as the data for that specific product. The loop uses custom code to enqueue each iteration as a separate task, enabling efficient processing of large CSV files without timeout issues.

const Mesa = require("vendor/Mesa.js");
const Loop = require('vendor/Loop.js');
module.exports = new class {
  script = (payload, context) => {
    // Loop over each item and enqueue child tasks for each matching item
    Loop.process(payload, context, (match, key) => {      
      match.key = match.key ? match.key : key;
      Mesa.output.nextOutput(match, {enqueue: true});
    });
  }
}

Get inventory Item ID for each item

App connector: Code • Time to complete: 0 minutes (Auto-configured)
Why this matters: Translates the human-readable SKU from your CSV into Shopify's inventory_item_id, which is the technical identifier required to update inventory levels via Shopify's API.

This custom code step uses Shopify's GraphQL API to search for a product variant matching {{loop.SKU}} from the current CSV row. The GraphQL query searches for "sku:[YOUR_SKU]" and returns the variant's inventory item ID. The code extracts the numeric ID from Shopify's GraphQL ID format (which looks like "gid://shopify/InventoryItem/12345") and stores it as {{custom.inventory_item_id}}. If no matching SKU is found, the code logs a message and stops processing that row without attempting an inventory update, preventing errors for SKUs that don't exist in your Shopify store.

const Mesa = require('vendor/Mesa.js');
const ShopifyGraphql = require('vendor/ShopifyGraphql.js');
module.exports = new class {
  script = (payload, context) => {
    const vars = context.steps;
    let inventoryItemIdGid = 0;
    const productSku = vars.loop.SKU;
    
    Mesa.log.info("Product SKU", productSku);
    
    // GraphQL query to find variant by SKU
    let query = `
      query($query: String!) {
        productVariants(first: 3, query: $query) {
          edges {
            node {
              displayName
              id
              sku
              inventoryItem {
                id
              }
              product {
                id
                title
              }

            }
          }
        }
      }
    `;
    
    const response = ShopifyGraphql.send(query, {
      "query": "sku:" + productSku,
    });
    
    Mesa.log.info("Response", response);
    
    // Extract inventory item ID from response
    if (
      response && 
      response.data &&
      response.data.productVariants &&
      response.data.productVariants.edges[0] &&
      response.data.productVariants.edges[0].node &&
      response.data.productVariants.edges[0].node.inventoryItem &&
      response.data.productVariants.edges[0].node.inventoryItem.id
    ) {
      inventoryItemIdGid = response.data.productVariants.edges[0].node.inventoryItem.id;
      vars.loop.inventory_item_id = inventoryItemIdGid.match(/\d+/)[0];
      
      Mesa.log.info("Inventory Item ID", vars.loop.inventory_item_id);
      Mesa.output.next(vars.loop);
    } else {
      Mesa.log.info('No Inventory Item ID found. SKU does not exist.');
    }
  }
}
Shopify logo icon

Set the new inventory level

App connector: Shopify • Time to complete: 3 minutes
Why this matters: Updates the product variant's inventory in Shopify to match the quantity from your CSV file, completing the sync between your external system and your store's inventory records.

This step sets the inventory level for the product variant using {{custom.inventory_item_id}} (from the SKU lookup), {{loop.Inventory}} (the quantity from the CSV), and a location_id that you configure during setup.

You need to find your Shopify location ID by going to Settings > Locations in Shopify admin, clicking on the location where you track inventory, and looking at the URL which will show a number like "12345678901"—that's your location ID.

The inventory is set (not adjusted), meaning the quantity in Shopify will exactly match the CSV value regardless of what it was before. This ensures your CSV is always the source of truth.

Ready to set this up? It only takes 13 minutes.

Our support team will even help you personalize this workflow for free.

Get started →

Make it your own!

Customize this workflow even further:

Send completion reports
Add steps after the loop ends to count successful updates, list any SKUs that weren't found, and send a summary email or Slack message showing how many products were updated and any errors encountered.
Archive processed files
Enable the "move_file" option in the FTP trigger settings to automatically move CSV files to an "archive" or "processed" folder after they're imported, preventing duplicate processing and maintaining a history of imports.
Handle inventory adjustments instead of sets
Modify the workflow to retrieve current inventory levels first, calculate the difference between CSV and current quantity, and use "adjust" instead of "set" to create an audit trail of inventory changes rather than absolute updates.
Support multiple locations
Add a "Location" column to your CSV and modify the custom code to map location names to IDs, enabling a single CSV to update inventory across multiple warehouses or retail locations.

Common questions

What happens if a SKU in the CSV doesn't exist in Shopify?

Can I use this to update inventory at multiple locations?

Does this workflow adjust inventory or set it to an absolute value?

Ready to start automatically updating Shopify inventory from CSV files on your FTP server?

7-day free trial • 13 min setup • Cancel anytime

Need help? Our automation experts will help you personalize this workflow for free. Contact support