@tsc_tech/medusa-plugin-woocommerce-migration
v0.0.2
Published
Complete WooCommerce to Medusa v2 migration plugin with streaming architecture, BullMQ-based checkpointing, and support for SQL dumps and CSV exports. Migrates products, orders, customers, taxonomy, and media with resume/pause capabilities.
Maintainers
Readme
@tsc_tech/medusa-plugin-woocommerce-migration
A Medusa v2 plugin to migrate WooCommerce data into Medusa. It migrates products, variants, and customers only. You upload WooCommerce CSV exports; the plugin uses a streaming architecture for large files and BullMQ for reliable, resumable jobs with pause/resume.
Compatibility
- Medusa:
>= 2.4.0(Medusa v2) - Node:
>= 20 - Redis: Required (for BullMQ job queues)
Installation
1. Install the plugin in your Medusa app
From npm (when published):
yarn add @tsc_tech/medusa-plugin-woocommerce-migration
# or
npm install @tsc_tech/medusa-plugin-woocommerce-migrationFrom a local path (development):
yarn add /path/to/tsc_plugin_woocommerce-to-medusa-migration
# or with yalc
yalc add @tsc_tech/medusa-plugin-woocommerce-migration2. Add the plugin to medusa-config.ts (or medusa-config.js)
Add the plugin to the plugins array and pass options. All configuration is provided by your Medusa app (via options and/or environment variables).
If using TypeScript (medusa-config.ts):
import path from "path";
import os from "os";
// Inside the plugins array:
{
resolve: "@tsc_tech/medusa-plugin-woocommerce-migration",
options: {
// The URL of your Medusa backend server (used by workers to call the ingest webhook)
backendUrl: process.env.MEDUSA_BACKEND_URL || "http://localhost:9000",
// Default currency for imported product/variant prices (e.g. USD, INR, BRL)
defaultCurrency: process.env.WOO_MIGRATION_DEFAULT_CURRENCY || "USD",
// Default shipping profile ID for migrated items (optional; can be resolved from Fulfillment module)
defaultShippingProfileId: process.env.WOO_MIGRATION_DEFAULT_SHIPPING_PROFILE_ID || "",
// Connection string for your main database (used for project isolation / namespacing)
databaseUrl: process.env.DATABASE_URL || "",
config: {
redis: {
host: process.env.REDIS_HOST || "localhost",
port: parseInt(process.env.REDIS_PORT || "6379", 10),
password: process.env.REDIS_PASSWORD || undefined,
db: parseInt(process.env.REDIS_DB || "0", 10),
},
upload: {
// Temporary folder for uploaded files during migration.
// Use system temp so the dev server file watcher does not restart when files are written (avoids "fetch failed" during ingest).
tempDir: path.join(os.tmpdir(), "woo-migration"),
},
},
},
},If using JavaScript (medusa-config.js):
const path = require("path");
const os = require("os");
// Inside the plugins array:
{
resolve: "@tsc_tech/medusa-plugin-woocommerce-migration",
options: {
backendUrl: process.env.MEDUSA_BACKEND_URL || "http://localhost:9000",
defaultCurrency: process.env.WOO_MIGRATION_DEFAULT_CURRENCY || "USD",
defaultShippingProfileId: process.env.WOO_MIGRATION_DEFAULT_SHIPPING_PROFILE_ID || "",
databaseUrl: process.env.DATABASE_URL || "",
config: {
redis: {
host: process.env.REDIS_HOST || "localhost",
port: parseInt(process.env.REDIS_PORT || "6379", 10),
password: process.env.REDIS_PASSWORD || undefined,
db: parseInt(process.env.REDIS_DB || "0", 10),
},
upload: {
tempDir: path.join(os.tmpdir(), "woo-migration"),
},
},
},
},3. Start your Medusa server
Ensure Redis is running, then:
yarn build
yarn dev
# or: npx medusa developThe plugin registers an admin UI route and API endpoints automatically.
Configuration reference
| Option | Description | Default / Env |
| -------------------------- | ----------------------------------------------------------------- | --------------------------------------------------- |
| backendUrl | Medusa backend URL (used by workers to call the ingest webhook) | MEDUSA_BACKEND_URL or http://localhost:9000 |
| defaultCurrency | Currency code for imported product/variant prices (e.g. USD, INR) | WOO_MIGRATION_DEFAULT_CURRENCY or USD |
| defaultShippingProfileId | Default shipping profile ID for migrated items | WOO_MIGRATION_DEFAULT_SHIPPING_PROFILE_ID or "" |
| databaseUrl | Main database connection string (used for project isolation) | DATABASE_URL or "" |
| config.redis | Redis connection for BullMQ (host, port, password, db) | REDIS_* or localhost:6379 |
| config.upload.tempDir | Directory for temporary uploads during migration | path.join(os.tmpdir(), "woo-migration") |
Important: Use a temp directory outside your project (e.g. path.join(os.tmpdir(), "woo-migration")) so the dev server file watcher does not restart when the plugin writes uploaded files. Using something like ./uploads/temp can cause the server to restart and the ingest step to fail with "fetch failed".
How it works
High-level flow
- Upload – You upload a WooCommerce CSV export from the Medusa Admin Woo Migrator page.
- Parse – A BullMQ worker reads the CSV in a streaming way and extracts raw records (products, variants, or customers).
- Transform – Another worker converts WooCommerce data into Medusa-shaped products, variants (with prices), or customers.
- Ingest – Workers send batches to the Medusa backend via the
/hooks/migration-ingestwebhook, which writes to the Medusa database (PostgreSQL) and creates store/region/price sets as needed for products.
Upload CSV → Parse (stream) → Transform (map to Medusa) → Ingest (HTTP → Medusa DB)Progress, job state, and checkpointing are stored in Redis, so you can pause and resume migrations.
How to connect and use it
- Redis – Must be running and reachable at the host/port you set in
config.redis. The plugin uses it for job queues and state. - Medusa backend – Must be running at
backendUrl. Workers callPOST {backendUrl}/hooks/migration-ingestto persist data. - Admin UI – After installing the plugin and starting the server, open your Medusa Admin and go to the Woo Migrator (or Migrations) section. From there you:
- Choose entity type: Products, Variants, or Customers
- For products/variants, optionally choose price currency for the migration
- Upload your WooCommerce CSV file
- Watch progress and use Pause / Resume / Cancel
- View Failed and Skipped items per job when the migration finishes
What gets migrated
The plugin supports CSV only and completes migration for these three entity types:
- Products – Simple and variable products; titles, descriptions, handles, status, categories, tags.
- Variants – WooCommerce variations mapped to Medusa variants with options (e.g. Size, Color), SKU, and prices. Prices are stored in the currency you choose at upload; the ingest hook ensures a store and region for that currency so prices show in the Admin price grid.
- Customers – WooCommerce customer exports mapped to Medusa customers.
Environment variables (in your Medusa app)
Set these in your Medusa app (e.g. .env); the plugin receives them only through the options you pass in medusa-config (as in the examples above).
| Variable | Purpose |
| -------------------------------------------------------- | ------------------------------------------------------------- |
| MEDUSA_BACKEND_URL | Backend URL for ingest webhook (e.g. http://localhost:9000) |
| WOO_MIGRATION_DEFAULT_CURRENCY | Default currency for migration (e.g. USD, INR) |
| WOO_MIGRATION_DEFAULT_SHIPPING_PROFILE_ID | Default shipping profile ID (optional) |
| DATABASE_URL | Database URL (used for project isolation) |
| REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_DB | Redis connection for BullMQ |
Admin UI
- Route – The plugin adds a route in the Medusa Admin (e.g. Woo Migrator or Migrations).
- Actions – Upload file, select entity type and currency, start migration, pause/resume/cancel, view job status and counts.
- Post-migration – For each job you can open Failed items and Skipped items to inspect errors or duplicates.
Prerequisites
- Node >= 20
- Medusa v2 (e.g. >= 2.4.0)
- Redis (for BullMQ)
- PostgreSQL (your Medusa database)
Project files: what’s required vs optional
Plugin runtime needs only:
src/– plugin source (built into.medusa/serverwhen you runmedusa plugin:build)package.json– name, dependencies, exports
Safe to remove (plugin will still work):
- Root
.jsfiles –analyze_csv.js,essential_fields_analysis.js,verify_csv.js,test-csv-parse.js,test-csv-parsing.js,test-full-flow.js,test-project-identifier.js– used for local testing/analysis only; not imported by the plugin scripts/–compare-woo-medusa-counts.js,compare-woo-medusa-report.js,debug-options-flow.js– dev utilities; not used at runtime- All
.mddocs –HOW_TO_IDENTIFY_VARIANTS.md,TESTING.md,PLUGIN_ARCHITECTURE.md, everything indocs/(e.g. CSV_*.md, GUJARATI docs,medusa-variant-create-payload.json) – documentation only - Shell scripts –
deploy-plugin.sh,deploy-yalc.sh,deploy-force.sh,debug-images.sh– deploy/debug helpers - Data/reports – any
.csvexports,compare-report.txt,csv-verification-report.txt,check-images.sql,wp-product-json– sample data or outputs - Config –
.yarnrc.yml,package-lock.json,.medusa-config/– useful for dev/install but not required for the plugin to run in a Medusa app
Removing any of the “safe to remove” items will not break the plugin’s upload → parse → transform → ingest flow. Keep them if you want docs and dev tools; delete them if you want a minimal repo.
More documentation
- HOW_TO_IDENTIFY_VARIANTS.md – How the plugin finds product vs variant from the CSV (Type, Parent column, and full parse → transform → ingest flow).
- PLUGIN_ARCHITECTURE.md – Project structure, queues, workers, mappers, and API endpoints.
- docs/PRICE_REGION_VARIANT_FLOW.md – How prices, regions, and variants are created during ingest.
- docs/ENV_USAGE_AND_MEDUSA_APP_CONFIG.md – Config flow and why
tempDirshould be outside the project.
License
MIT
