Skip to main content
Every import type follows its own rules for two questions:
  1. What does it create? - which records appear in your workspace.
  2. When does it create a new record vs. reuse an existing one? - how a row is matched against data you already have, and what happens when it matches.
Knowing these rules lets you re-run an import without guessing whether you’ll end up with duplicates.

At a glance

Products, materials, suppliers, locations, and BOMs are safe to re-run - matching records are reused or updated in place, so you won’t create duplicates. Activity, air travel, and transport imports are not - every row becomes a new record each time you import the file. See Activity data, air travel, and transport below.
The sample rows below use Variable’s canonical column names. Your file’s headers don’t need to match - the column mapping step lets you map any header to the right field.

Products

Creates a product owned by your company for each row.
  • Matched by: SKU, scoped to your company. If a row has no SKU, the product name is used instead.
  • On a match: the import match mode decides. By default (Create new only) the existing product is reused and left untouched. Choose Overwrite existing or Fill missing only to update its scalar fields - weight, codes, description, notes - from your file; its links (supplier, datasets, model inputs) are never changed.
  • Created new when: no product matches - by SKU, or by name when the row has no SKU. A SKU-less row gets a SKU generated from its name on creation.
Sample rows:
Alongside weightQuantity/weightUnitCode, product rows can carry lengthQuantity/lengthUnitCode, volumeQuantity/volumeUnitCode, and areaQuantity/areaUnitCode. Map a quantity column without its unit and Variable assumes the SI base unit (m, m3, m2); leave a dimension blank and it stays unset.

Materials

Creates a source product (a material or supplier part) for each row, and a supplier company when supplier columns are present.
  • Matched by: SKU, scoped to the owning supplier. The supplier is matched first by UUID, then by your internal supplier ID, then by supplier name. Name is the fallback when a row has no SKU.
  • On a match: the import match mode decides. By default (Fill missing only) blank scalar fields on the existing material are filled in from your file, while values you’ve already set are kept. Choose Create new only to leave matched materials untouched, or Overwrite existing to replace their values; the supplier link and any datasets or inputs are never changed in any mode.
  • Created new when: no material matches - by SKU, or by name when the row has no SKU. A SKU-less row gets a SKU generated from its name on creation.
Sample rows:
Alongside weightQuantity/weightUnitCode, material rows can carry lengthQuantity/lengthUnitCode, volumeQuantity/volumeUnitCode, and areaQuantity/areaUnitCode. Map a quantity column without its unit and Variable assumes the SI base unit (m, m3, m2); leave a dimension blank and it stays unset.

Bill of materials (BOM)

Creates inputs (line items) on the product you’re importing into, plus any supplier parts and materials the rows reference. See What happens after upload for the full 3-level structure.
  • Matched by: products are matched by SKU and ownership; individual inputs are matched by their source product, quantity, and unit.
  • On a match: products are reused and left untouched. Inputs are only added to a product that was created during this import, is still UNKNOWN, or has no inputs yet. A product that’s already LIVE with inputs is treated as fully modeled and keeps its existing inputs.
  • Created new when: the product or input isn’t already present under those rules.
Sample rows (a root product on level 0, with a supplier part and its material on level 1):
If a re-import isn’t adding inputs to a product, the product is most likely already LIVE with a model. See Import troubleshooting for how to add to it.

Suppliers

Creates a supplier company for each row, plus contacts when contact columns (name or email) are present.
  • Matched by: UUID, then your internal supplier ID, then supplier name.
  • On a match: the existing supplier is reused and left untouched. A contact is added only when no contact with the same email or name is already on that supplier.
  • Created new when: no supplier matches by ID or name.
Sample rows:

Locations

Creates a named location for each row, optionally geocoded to coordinates when address details are provided.
  • Matched by: location name, within the owning company - the company named in the companyId column, or your own company for locations you hold directly.
  • On a match: the existing location is reused. Address fields from your file fill in blanks but do not overwrite values that are already set.
  • Created new when: no location with that name exists for that company.
Sample rows:

Activity data, air travel, and transport

These three types record transactions and events - a purchase, a sale, a flight, a shipment. Each row becomes one activity record. Air travel and transport are activity types with their own columns (flight details, logistics weight and distance, and so on).
  • Matched by: nothing. Imported activity rows are not matched against existing activities.
  • Always created new: every row produces a new record on every import.
Sample rows - activity data:
Sample rows - air travel:
Sample rows - transport:
Because activity rows aren’t deduplicated, re-importing the same activity file will create the records again. Import each period’s data once. To correct activities you’ve already imported, edit or delete them in the app or via the API rather than re-importing - see the Activity API.

Import match mode (products and materials)

Product and material imports let you choose what happens to matched rows. A match-mode selector appears on the upload screen for these two import types. The default depends on the type - product imports start on Create new only, material imports on Fill missing only - but you can switch to any mode before you submit:
  • Create new only (default for product imports) - matched rows are skipped, and only new items are added. This is the safe, no-surprises option, and the same way supplier and BOM imports already behave.
  • Overwrite existing - the values in your file win. Each scalar field on the matched item is replaced with the imported value wherever your file provides one.
  • Fill missing only (default for material imports) - only fields that are currently empty are filled in; values you’ve already set are kept. A stored 0 or an empty text value counts as set and is preserved - Variable treats zero as a value and only “missing” as missing.
Use overwrite or fill-missing to backfill enriched source data - weights, CPC/HS codes, descriptions, notes - onto items you created earlier, without re-keying them by hand.
Scalar fields only. Overwrite and fill-missing update an item’s own fields - weight, SKU, codes, description, notes, and the like. They never touch its relationships: the supplier, assigned datasets, and bill-of-materials inputs on an existing item are left exactly as they are, in every mode. Updating those by import is a planned follow-up.
Because matched rows are still deduplicated by SKU (or name), re-importing never creates duplicates regardless of mode - the only question is whether matched items are left alone, overwritten, or topped up.

Undoing an update

Deleting an import doesn’t just remove the items it created - it also reverts the scalar updates it made to pre-existing items. Overwritten fields are restored to their prior values, and fields it filled in are cleared again. The revert is guarded: any field you (or a later import) changed after the import is left exactly as it is, so a delete never clobbers newer edits. When some fields are skipped for that reason, the app tells you how many couldn’t be reverted.

Other types

Suppliers and BOMs always reuse, not update a matched record, so a re-import won’t rewrite curated data. Locations are a partial exception - a re-import fills in address fields that were previously blank but won’t overwrite values that are already set. Activity, air travel, and transport rows are never matched and always create a new record. To change one of these after import, edit it directly in the app or via the API.

Next steps