Skip to main content
Migration guide

Magento to Vendure

A practical account of Colour Graphics's migration, run by Pinelab: what ported as data, what had to be rebuilt, and where the 400 hours went.

Effort

400 hours

The whole migration, backend to storefront. For a similarly scoped project, we'd discuss a planning range of roughly 350–450 hours, not promise the same total. That range is anchored in this project, not a general Magento-to-Vendure estimate.

Elapsed

2 months

Roughly, and not the end of it. Xero and further shipping work continued after go-live.

Team

3 developers

Three developers worked on the project: two full-stack developers and one frontend developer. The client supplied the designs.

Where it went

40 / 40 / 20

Our approximate split was 40% backend configurable products and integrations, 40% storefront development, and 20% data migration. Moving the data was the small part.

In short

A data migration around one rebuilt calculation

Colour Graphics sells large-format print. A banner has no price until a customer gives it dimensions, options and a delivery method, and the rules turning those into a number had grown into a Magento 2 plugin that worked and had become hard to maintain.

So the project split cleanly in two. Customers, orders, blogs, product content and their original slugs came across as records, on import scripts. The pricing engine and the storefront did not come across at all: the configurable products were modelled again in Vendure, and the storefront was rebuilt in Astro against the GraphQL Shop API. Pricing now lives in a Google Sheet instead of in individual products.

The complexity of product calculations and the number of launch integrations drive that effort up or down. So does the willingness to simplify old behaviour instead of reproducing every feature.

At a glance

The project in four moves

  1. 1

    Import what is only data

    Customers, orders, blogs and product content move across as records, original slugs included.

  2. 2

    Model the configurable products again

    The old plugin's stored JavaScript calculations are not ported; options and pricing are redesigned in Vendure and driven from a spreadsheet.

  3. 3

    Rebuild the storefront

    A new Astro storefront on the GraphQL Shop API carries dimensions and selected options all the way through checkout.

  4. 4

    Launch one brand, then the delta

    Colour Graphics goes live, orders placed since the export are imported behind it, and Fabrix follows later on the same Vendure instance.

Each move has its own chapter below, traps included.

Who this is for

This guide is for printing businesses where customers configure a product rather than choose a fixed-price item. Colour Graphics is a UK large-format print specialist selling products such as banners and wall coverings, with different pricing for general and wholesale customers.

Dimensions, selected options and delivery requirements all affect the order. We moved their Magento 2 shop to Vendure, rebuilt the storefront in Astro and later extended the setup to another brand. The main challenge wasn't moving product descriptions, it was rebuilding the rules behind each purchase.

Why they left

The client's initial request was direct: they wanted to move away from the bloat, lack of speed and restrictions they were experiencing in their Magento 2 setup. They also wanted a long-term development partner. This wasn't a shop they expected to finish and leave untouched.

The clearest practical problem was pricing maintenance. Many products were priced by area: height × width, multiplied by a square-metre rate, with further calculations for product options. General and wholesale customers needed different prices.

Their existing pricing plugin worked. It gave them considerable flexibility. But changing prices meant editing products individually. That was time-consuming for a business that regularly adjusted its catalogue and pricing.

Magento 2 had supported a functioning business with this custom logic and it worked, but this implementation had become difficult to maintain. This helped us shape our plan: preserve the useful business data and behaviour, but don't reproduce every old implementation decision.

Pricing they could maintain in a spreadsheet

The client wanted to manage pricing through Google Sheets instead. Updating rates in a spreadsheet was a better fit for their daily work than repeatedly opening individual product configurations.

Delivery added another layer

Large-format printing doesn't fit neatly into a flat shipping charge. Dimensions, weight and total area can matter, and a dedicated vehicle needs a distance-based calculation.

What we were actually moving

The data migration covered customers, orders, blogs and product content. Product names, descriptions and slugs were part of the export. Keeping existing slugs mattered because we wanted established product URLs to survive the move.

The more difficult inventory was the product configuration. A banner isn't necessarily one variant with one price. The customer supplies dimensions and chooses options, and those inputs determine what it costs. The old plugin's configuration didn't map directly onto our new model.

We therefore treated product content and product behaviour as separate pieces of work. Content could be imported. Configurable options needed to be redesigned and manually defined in the new system.

Historical orders needed their own decisions. We migrated order line data, prices and address details, but did not reconstruct the original Magento promotions as Vendure promotions. Preserving what the customer ordered and the recorded prices was more valuable than recreating the rules that had produced every historical discount.

What the first storefront launched with

  • Google Sheets pricing integration.
  • Different pricing for general and wholesale customers.
  • Purchase-order checkout for authorised credit-account customers, built as a custom payment method.
  • Distance-based shipping calculations.
  • Mollie for payments.

Blogs moved into Directus, while the storefront was rebuilt in Astro. We launched Colour Graphics first and moved Fabrix later, using Vendure channels to support multiple storefronts.

Separate content from business rules

We started with a vanilla Vendure instance and exported the existing Magento data. We wrote import scripts for customers, orders and product content. Blog and product content exports used CSV, and blogs were imported into Directus.

Customers, blogs and product content were relatively straightforward. The surprise was how little of the configurable-product setup could sensibly be treated as ordinary migration data. Importing a calculation isn't enough if the new application interprets product options differently.

Data migration represented about 20% of the overall effort. Across a roughly 400-hour project, that's around 80 hours. These are approximate allocations, not separate calendar phases: the work overlapped.

Today, we would manage blogs with our CMS plugin within Vendure's React Dashboard instead of maintaining Directus as a separate content system.

Storefront

Rebuild the storefront rather than translate a theme

We built a new Astro storefront against Vendure's GraphQL Shop API. The client supplied the designs.

The initial request had been for something visually similar to the existing shop. In practice, the existing themes were dated, and a redesign was needed anyway. We didn't attempt to translate the Magento theme into the new storefront.

The product configurator was central to this work. The storefront needed to collect dimensions and selected options, show the resulting price and carry those selections through the purchase flow. This was much more than rendering imported product descriptions.

Storefront development accounted for roughly 40% of the effort, or around 160 hours. An important expectation to resolve early was that a headless backend doesn't provide the finished customer-facing shop.

Rebuild the calculations, then cut over

Another roughly 40% went into backend configuration, configurable products and integrations.

For calculated product prices, we implemented Vendure's OrderItemPriceCalculationStrategy. In our implementation, the strategy reads the selected configuration, calls the calculation service and returns the appropriate trade or retail price. Products without a configurator use the default pricing strategy.

This gave the calculations an explicit place in the backend rather than carrying over the Magento plugin model. We also connected Google Sheets pricing, purchase-order checkout, distance-based shipping and Mollie payments.

Checking every URL before launch

Before launch, we compared URLs on the live site with those on the development site using Linkinator. Some products had been removed and some categories renamed or reordered. We created redirects for missing or moved pages rather than assuming preserved product slugs covered everything.

Going live, then importing the order delta

We went live with Colour Graphics first, then migrated the delta of orders placed since the earlier export. Active carts were not migrated. The Fabrix storefront followed later rather than making the first cutover a multi-brand launch.

What ported cleanly, and what got rebuilt

Ported or preserved

  • Customer records were straightforward to migrate.
  • Product names, descriptions and original slugs could be imported.
  • Blog content moved into Directus.
  • Historical order lines, prices and address details were retained.
  • Existing URLs were retained where possible.

Rebuilt, changed or deliberately left behind

  • The Astro storefront was a complete rebuild using client-supplied designs.
  • Configurable product options were redesigned and manually redefined.
  • The old database-stored JavaScript calculation model was replaced with backend calculation code.
  • Applied Magento promotions were not reconstructed as Vendure promotion rules.
  • Removed products and changed category URLs needed redirects.

The important boundary was between records and executable behaviour. Product descriptions could move across; pricing rules needed rethinking. For historical orders, we preserved the commercial record without reproducing the original pricing engine.

What we would warn you about

The traps

Treating product options as importable data

The old plugin was flexible, but its stored JavaScript calculations were hard to test. Trying to carry that model across unchanged would have preserved the maintenance problem as well as the functionality.

We redesigned the options and dropped some features in favour of a more maintainable implementation. The lesson is to inspect representative configurable products before estimating the migration. A catalogue export doesn't reveal the full complexity of selling them.

Underexplaining the storefront work

We needed to explain that, in this setup, the storefront was custom development. Vendure provided the commerce backend; it wasn't a replacement theme we could apply to the existing shop.

That flexibility was useful, but it cost time and money. Make this explicit before agreeing scope, particularly when the starting request is to keep a similar design.

Trying to reconstruct historical promotions

We couldn't reconstruct the applied Magento promotions in Vendure cleanly. We kept order line information and recorded prices instead.

Decide what historical orders need to support before building the importer. Reading an old order and rerunning its original discount logic are different requirements.

Underestimating calculation edge cases

Most post-launch issues came from configurable-product pricing edge cases, not from moving text or customer records. We didn't encounter serious conversion-stopping bugs, but the calculations still needed attention.

For another migration, we'd put even more emphasis on agreed pricing examples before launch: different dimensions, quantities, options and customer types. Those examples give the client and developers something concrete to check together.

Go-live and afterwards

We launched Colour Graphics first and imported the order delta afterwards. Active carts were excluded, so cart continuity was not part of the migration promise. Fabrix moved later, using the multi-storefront setup built around Vendure channels.

After launch, we observed a slight traffic drop followed by a gradual increase beyond the previous results. That's the outcome of this project, not a traffic guarantee for another migration.

Development continued after launch, including Xero integration and further specialised shipping calculations. The migration established the new shop; it didn't finish its development.

Where this approach does not fit

We wouldn't recommend this approach if you expect your existing Magento 2 shop, theme and plugins to move across unchanged. That wasn't what happened here: the storefront and configurable-product behaviour were substantial rebuilds.

If your current shop meets your needs and you don't have a budget for custom storefront development and ongoing maintenance, this may be the wrong project.

It fits better when you want to preserve valuable data while changing how the shop works. For Colour Graphics, that meant keeping customers, content and order history while rebuilding the calculations and customer experience around their business.

Need help assessing a Magento-to-Vendure migration? Contact Pinelab.

Martijn van de Brug
Written by

Martijn van de Brug

Founder (and still developer), Pinelab

Founder and developer at Pinelab, passionate about open source and making knowledge freely available for others to learn from, improve, and build upon.

The author's views are their own and may not reflect the views of Vendure.

Next step

Planning the move?

Bring the pricing rules and product configurations your Magento build made you write. A partner who has run this migration, or our own engineers alongside your team, will sort them into what ports, what you redesign and what you leave behind before anyone writes code.