Skip to main content

Product Import Export Plugin

A Vendure plugin for importing and exporting product data via CSV. Supports bulk product management and data migration between environments.

Features​

  • Import – Bulk upload products from CSV with validation, custom fields, assets, facets, and variants
  • Export – Export products to CSV with selected fields; export all products or a selection
  • Storage strategies – Store exported files in S3 or locally on disk (with automatic fallback)
  • UI – Admin UI and Dashboard integration for import and export

Dashboard UI

Compatibility​

Vendure ^3.6.0

Getting started​

npm install @haus-tech/product-import-export-plugin

Configuration​

Add the plugin to your Vendure configuration.

export const config = {
plugins: [
ProductImportExportPlugin.init({
importOptions: {}, // Configure import options
exportOptions: {
storageStrategy: 's3', // 's3' | 'disk'
s3Options: {
bucket: 'your-bucket',
region: 'your-region',
credentials: {
accessKeyId: '...',
secretAccessKey: '...',
},
},
},
}),
],
}

Configuration Options​

Import options​

OptionTypeDefaultDescription
updateProductSlugbooleantrueUpdate product slug from the name field in the CSV
restoreSoftDeletedbooleantrueRestore soft-deleted products/variants found by id or SKU during import. If false, new products will be created instead.
storageStrategyImportJobStorageStrategylocal diskStrategy instance for queued import file storage and retrieval.
storageStrategyFactory(injector: Injector) => ImportJobStorageStrategyundefinedFactory for DI-aware strategy creation (recommended for S3/remote storage).
importJobStorage'local' | 's3''local'Deprecated compatibility flag. Prefer storageStrategy / storageStrategyFactory.

Available import storage strategies:

  • LocalImportJobStorageStrategy (default)
  • S3ImportJobStorageStrategy

Export options​

OptionTypeDefaultDescription
defaultFileNamestring'products_export.csv'Default filename for exports
exportAssetsAsOptions('url' | 'json')[]['url', 'json']Available formats for asset export
defaultExportAssetsAs'url' | 'json''url'Default asset export format
defaultExportFieldsstring[]See aboveFields that will be pre-selected in the export UI
requiredExportFieldsstring[]['name', 'sku']Fields that must always be included
storageStrategy's3' | 'disk''disk'Where exported files are stored
s3OptionsobjectundefinedS3 configuration (required when storageStrategy is 's3')

Storage strategy​

The plugin supports configurable storage for exported files:

  • S3 – Stores export files in an S3-compatible bucket
  • Disk (default) – Saves files locally on the server

CSV Format for Import​

Required columns​

  • name – Product name (use name:en, name:sv etc. for multiple languages)
  • sku – Variant SKU (unique per variant)

Optional columns​

ColumnFormatExample
name, slug, descriptionText, or name:en, name:sv for translationsMy Product
assetsPipe-separated URLs, or JSON [{"url":"...","name":"..."}]https://example.com/1.jpg|https://example.com/2.jpg
facetsfacet:value pairs, pipe-separatedBrand:Acme|Category:Electronics
optionGroupsPipe-separated group names. Use name:code to share a group across products (see Sharing option groups)Size|Color or size:shoe-size
optionValuesPipe-separated values (order matches option groups)Large|Blue
priceNumber (in smallest currency unit)9999
taxCategoryTax category namestandard
stockOnHandNumber100
trackInventorytrue or falsetrue
variantAssetsSame format as assetshttps://example.com/variant.jpg
variantFacetsSame format as facetsMaterial:Cotton
enabledtrue or falsetrue
Custom fieldsColumn name = custom field name; value depends on field typeAdd columns for any Product or ProductVariant custom fields defined in your Vendure config

Import behavior rules​

  • If a column is omitted from the CSV header, that field is left unchanged on existing products/variants.
  • If a column exists in the header but the cell is empty, that field is explicitly cleared.
  • For products with more than one variant, optionGroups and optionValues are required.

Sharing option groups​

By default, each product gets its own option groups. To share an option group across multiple products (e.g. a common "Size" group for all shoes), use the name:code syntax in the optionGroups column: size:shoe-size. All products that reference the same code will share a single option group. Products using a plain name (e.g. just size) will each get their own independent option group.

...optionGroups , optionValues , ...
# Each shoe product shares a single "shoe-size" option group:
"size:shoe-size" , Small , ...
"size:shoe-size" , Medium , ...
# This product gets its own independent "size" group:
"size" , 4GB , ...

The first product to reference a given code defines the full set of option values for that shared group; subsequent products may use any subset of those values. Codes are language- agnostic — only the name portion before the colon is translated per language column (optionGroups:en, optionGroups:sv, etc.).

Multi-language support​

Use language-specific columns by suffixing the field name with the language code. The language codes must match those configured in your Vendure instance (e.g. en, sv).

Column patternExample columnsUse case
name:en, name:svProduct name per langTranslated product names
slug:en, slug:svSlug per langTranslated URLs
description:enDescription per langTranslated descriptions
facets:en, facets:svFacets per langTranslated facet names and values
optionGroups:enOption groups per langTranslated option group names (e.g. Size, Color)
optionValues:enOption values per langTranslated option values (e.g. Large, Blue)

Example CSV with English and Swedish:

name:en,name:sv,sku,facets:en,facets:sv
"Red Shirt","Röd tröja",SHIRT-001,"Color:Red|Size:Large","Färg:Röd|Storlek:Stor"

Multiple values (pipe separator)​

Fields that can have multiple values use the pipe character | as a separator:

  • Facets: Brand:Acme|Category:Electronics
  • Option groups: Size|Color
  • Option values: Large|Blue (order matches option groups)
  • Assets: https://example.com/1.jpg|https://example.com/2.jpg

Usage​

note

The Admin UI offers basic import and export. Some features such as the export-all option and the list of exported files are only available in the Dashboard. New features will be added to the Dashboard only.

Importing products​

  1. Create a CSV with the columns above.
  2. Go to the Admin UI or Dashboard and open the Product Import section.
  3. Upload the CSV and choose options (update slugs, restore soft-deleted, main language).
  4. Select the update strategy: merge (keep existing facets/assets) or replace (overwrite).
  5. Start the import.

Exporting products​

  1. In the Admin UI or Dashboard, select products to export (or use bulk export).
  2. Configure export fields (assets, facets, custom fields, etc.).
    • For products with more than one variant, optionGroups and optionValues must be included.
    • productId is not available as a selectable export field.
    • If customFields are not selected, no custom-field columns are written to the CSV.
  3. Choose asset format: URL or JSON.
  4. Start the export (it is added to a job queue and runs in the background).
  5. Download the CSV when the export is complete. Your downloaded files will be listed in the export view.

Export settings

Optional: Email notification on export complete​

If you use @vendure/email-plugin, you can add an email notification when an export finishes from the /email subpath.

The plugin now provides a default fallback template for product-export-complete/body.hbs.
If you define your own template in your app's template directory, your template takes precedence. Note: templates for @vendure/email-plugin should be valid MJML.

import path from 'path'
import {
DefaultEmailPlugin,
FileBasedTemplateLoader,
defaultEmailHandlers,
} from '@vendure/email-plugin'
import {
withProductExportedHandler,
withProductExportedTemplateFallback,
} from '@haus-tech/product-import-export-plugin/email'

export const config = {
plugins: [
DefaultEmailPlugin.init({
handlers: withProductExportedHandler(defaultEmailHandlers),
templateLoader: withProductExportedTemplateFallback(
new FileBasedTemplateLoader(path.join(__dirname, '../static/email/templates')),
),
}),
],
}

Resources​