Migrating away from Saleor to a custom Solidus store
TL;DR
Difficulty: Intermediate
- Saleor is genuine open source under the BSD 3 clause licence, built in Python, Django and GraphQL, so leaving it is a question of fit, not of getting your data back.
- The catalogue exports to CSV or XLSX through the product export; customers and orders come through the GraphQL API, 100 records a page, and self hosted shops also have direct PostgreSQL access.
- The honest wedge is one owned Rails application instead of a Python back end and a separate React storefront, one accountable builder, and leaving Saleor Cloud pricing.
- Saved cards and tokens live with the gateway, so keeping the same Stripe or Adyen account means they do not move at all; subscriptions are the item to plan first.
- Stay on Saleor if you want and use the headless, composable, multi storefront architecture and your team is fluent in it.
What to read first
Saleor is good software, so the reason to leave it is rarely lock in. The code is open source and the data is yours, whether you self host or run Saleor Cloud. The honest reason a business moves to a custom Solidus store is fit: one owned Rails application instead of a Python back end and a separate React storefront, one accountable builder instead of two disciplines, and an exit from Saleor Cloud pricing for a shop that has outgrown the headless model. In this article I set out what Saleor actually is, what you own and what is softly locked, how its GraphQL export really works, and how a careful move to Solidus runs, with the deep data detail linked to the guides in this series. I also say plainly who should stay.
The email that begins a Saleor move
Because Saleor is good software, the message I get about it is a different kind of message. It seldom complains that the data is trapped or that a vendor has the business by the throat. It usually runs along these lines. We started on Saleor two years ago when a developer set it up as a GraphQL store with a React storefront, it runs fine, but that developer has moved on, finding people who know Python and GraphQL and also a separate front end is hard, and I would like one person who owns the lot. Or: the Saleor Cloud invoice keeps climbing, and I am no longer convinced the headless machinery pays its way for a shop my size.
This is my honest answer for a business thinking of leaving Saleor for a custom shop on Solidus, the open source Ruby on Rails commerce framework I build on. I will keep it fair, because Saleor has earned that. The code really is yours, the data is yours, and for the right team Saleor is a strong choice. The reason to move is almost never lock in. It is fit. So most of this article is about what fit means in this case, what genuinely moves, and where the actual work sits.
For the deep, platform independent detail, how customer accounts, catalogues, orders and saved cards move in general, I point to the data type guides in this series instead of restating them. Begin with the pillar, what moves and what does not.
What Saleor is, and who should stay on it
Saleor is candid about itself. Its own project file describes a headless ecommerce platform built with Python, GraphQL, Django and React, released under the BSD 3 clause licence.1 The repository home page calls it a GraphQL native, API only platform for composable commerce, and puts "headless and API only" and "GraphQL only" among its defining features.2 The architecture overview states that the engine is written in Python and that the API runs GraphQL over HTTP or message queues, around a lean core with a rich ecosystem of external applications.3
Two of those words carry the rest. "Headless" means no bundled shop front ships with Saleor. You build the storefront yourself, typically in React or Next.js, against the GraphQL API, and you run the dashboard as a separate application. "Composable" means the back end is a set of commerce building blocks that you assemble and extend through apps and webhooks. It is a deliberate, modern design, and for its purpose it is genuinely good.
So who should stay on Saleor? A team that wants composable, event driven, GraphQL commerce, that serves several storefronts or sales channels from one back end, that employs or can recruit Python and front end engineers, and that is glad to own that architecture. If Saleor suits your business and your people work well in it, a move to Solidus is a sideways step that costs money and wins nothing. I would tell you as much in the workshop. If you are simply weighing modern open source options against one another, that is a comparison rather than a migration, and leaving Medusa belongs to the same category.
Who outgrows it is the mirror image. A single shop that gains nothing from the headless split. An owner who wants one accountable builder rather than a Python back end, a React front end, and whoever keeps the pair in step. A business that would sooner live in the Rails and Solidus ecosystem. And a shop on Saleor Cloud that has studied the bill.
What you own, and what is genuinely locked
Here I have to tread carefully, because the usual migration argument does not hold. Run the self hosted edition and all of it is yours: the source, the PostgreSQL database and every row inside it. The BSD licence even lets you keep your own changes private, with no obligation to publish them.4 Run Saleor Cloud and your data is still yours and you are free to leave. What you do not own is the running infrastructure, and the GraphQL API is the door in and out. Saleor's own stance is that Cloud is the best way to run the product and, once total cost of ownership is counted, the most economical,4 and for plenty of teams that is a fair reading.
None of that is a trap. If anyone has told you that leaving Saleor means losing your data, they are mistaken, and who actually owns your business data is worth your time before you take a vendor at their word on the point. What is "locked", in the soft sense, is the shape of the thing: GraphQL only, headless, a storefront you maintain separately, Saleor Cloud pricing where it applies, and the ordinary ties to third parties that every platform carries, chiefly the payment gateway holding your card tokens and whatever drives your subscriptions. I will take them in turn.
The export and API reality
Saleor is API first, and that API is GraphQL, with no REST interface to fall back on.2 That colours every extract you will run.
For the catalogue there is a built in product export. The dashboard and the exportProducts mutation produce a CSV or XLSX file, scoped to all products, a filtered selection, or a list of IDs, with the fields and column order you choose, and the finished file lands as a download link by email.5 It covers products and variants, with attributes, stock quantities and per channel prices, and it is the cleanest single tool available. It does not export customers or orders.
Those come through the GraphQL API by way of scripted queries. Three limits set the pace. Paginated fields return at most 100 items per page, using cursor based pagination, so a full extract is a loop that follows cursors.6 Query cost is reckoned from the number of objects requested rather than the number returned, and the server refuses anything above its ceiling, stating the cost and the limit in each response.6 On rate limiting the picture divides: free Saleor Cloud sandboxes permit 120 requests a minute and paid ones 2,000, beyond which the API answers HTTP 429, while production Cloud environments and self hosted deployments carry no fixed limit, though production may throttle traffic that harms the service.6 In practice a migration off Cloud is a patient, measured crawl of the API, written once and rerun until it is dull.
Host it yourself and there is a shorter route too: direct access to the PostgreSQL database, the quickest way to shift a large catalogue and order history in bulk. On Cloud there is no database access, so the GraphQL API and the product export are the entire kit.
One thing never arrives in usable form, on Saleor as anywhere: passwords. They are stored hashed, so customers set a fresh one on their first visit to the new shop. That is a campaign to plan, not a technical wall, and the customer accounts and addresses guide shows how to run it without flooding the inbox on cutover day.
The honest wedge: one application rather than two
Headless is a feature, not a flaw. For a smaller shop it is also the nub of the matter. On Saleor you run, at least, the Python engine, a storefront you built and maintain, and the dashboard, with apps and webhooks around them for payments and the rest.3 That is two or three codebases, two or three deployment pipelines, and two skill sets: back end Python and GraphQL on one side, a JavaScript storefront on the other. For a large team running several channels, that separation earns its keep. For a single shop it is a great many moving parts to hold in step, and the day the developer who understood both leaves is the day the strain begins.
A Solidus shop is one Ruby on Rails application. Solidus is open source under the BSD 3 clause licence, ships a REST API with it, and is an ordinary Rails app with the testing tools, deployment path and hiring pool that follow.7 You can still go headless when the need arises: headless and API first Solidus shows how the same shop can later feed a mobile app or a second storefront. The point is that you are not forced into the split on day one for a shop that does not need it. One application, one accountable builder, one place to look when something breaks. That, far more than any argument about data, is why a certain sort of Saleor shop is better served by Solidus.
Payments, saved cards and the gateway
Saleor does not process payments itself. It connects to gateways such as Adyen through apps and transaction webhooks, and the card data and reusable tokens live with the gateway, not inside Saleor.85 That is welcome news for a move. The best case takes the hardest question off the table altogether: if your shop already pays through its own Stripe, Adyen or similar account, the new Solidus shop connects to that same account and the saved cards stay precisely where they are.
If instead you are switching gateway as part of the move, saved cards travel only between providers certified to PCI DSS Level 1, and even then the export is the cards alone, not the subscriptions or the payment history attached to them.9 This is the item for the first conversation, not the last week, and the payment tokens and saved cards guide lays out the questions to put to your gateway before you commit to a date.
Subscriptions, if you run them
Saleor's core is a set of commerce primitives rather than a subscriptions engine, so recurring billing on Saleor is usually an app or an external service wired in through webhooks. The practical upshot for a move is that "what actually runs the subscriptions, and where do the schedules and the mandates sit" is the question you settle before anything else, because an active subscription is the hardest object in any migration. The subscriptions and recurring payments guide walks the cases, from a clean cutover to a gradual handover where both systems run side by side for a billing cycle or two.
SEO and the redirect map
Because the storefront is yours on Saleor, so are the URLs. Whatever paths your React or Next.js app uses for products, categories and content are the ones carrying your rankings and your inbound links, and they must land somewhere sensible on the new shop. The rule is the same as for any move: list every old URL that drew a visit or a link in the last year, map each to its new address, and serve a permanent redirect, a 301 in nearly every case, pointing straight at the final destination rather than through a chain. Keep the redirects for a year at least, and for good if you can.10 The products and catalogue data guide covers how the catalogue and its URLs come across together, which is where most of the redirect map comes from.
The move, mapped to the data guides
Here is the shape of a Saleor move on one page. Each row points to the guide that carries the detail, so this article stays about Saleor and does not repeat what those cover.
| What | How it leaves Saleor | Where the detail lives |
|---|---|---|
| Products, variants, prices, stock | Product export to CSV or XLSX, or a direct PostgreSQL read when self hosted | Products and catalogue data |
| Customers and addresses | GraphQL queries, 100 per page, cursor paged, passwords reset not migrated | Customer accounts and addresses |
| Order and purchase history | GraphQL queries as read only history, recent years not everything | What moves and what does not |
| Saved cards and tokens | Stay with the gateway, so keeping the account means they do not move | Payment tokens and saved cards |
| Subscriptions | Depends on the app or service that runs them, plan this first | Subscriptions and recurring payments |
| Storefront, URLs, redirects | Rebuilt on Solidus, every old URL mapped to a 301 | Products and catalogue data |
The shop stays the controller of its customer data throughout, and the platform, the host and I are each processors who need a written processing agreement under Article 28 of the General Data Protection Regulation.11 A migration needs no fresh consent from every customer, but it does need the consent records, with their timestamps and wording, carried across rather than flattened to a yes or no flag.
A worked example: Shandon Roastery, Cork
Shandon Roastery (shandonroastery.example) is an invented Cork coffee brand turning over roughly €1.2 million a year online. It roasts to order, sells bags and brewing kit, and runs a coffee club that ships every two or four weeks, about a third of its revenue. Two years ago a developer built it on Saleor Cloud Select, with a Next.js storefront and Stripe for payments, and it has served it well.12 The trouble is people, not the platform. That developer now works on their own and is hard to book, the owner cannot find one person strong in both Python and the React storefront, and the Cloud subscription plus the coffee club tooling has become a line she notices. She wants one shop, one builder, and the Rails ecosystem she already uses for the roastery's back office tools.
I would run it in this order. First the two questions that can sink a date. Payments: the shop already owns its Stripe account, so the Solidus build connects to that same account and the saved cards simply stay, which lifts the hardest item off the table. Subscriptions: the coffee club runs through an app wired into Saleor, so before anything else I pin down where the schedules and the Stripe mandates actually live, and plan to move the club as its own small project, very likely with both systems running for one billing cycle so no renewal slips.
Then the data. The catalogue comes out through Saleor's product export as CSV, variants, attributes, stock and per channel prices included, and maps cleanly onto Solidus products and variants.513 Customers and order history come through the GraphQL API, a measured crawl that follows cursors 100 records at a time and stays well within the Select plan's limits,6 brought in as read only history for the last three years with the full export archived. Passwords are left untouched, and every account is recreated in the new shop ready to activate, with a service message before cutover telling club members and customers what to do on their first visit.
The storefront is rebuilt as part of the Solidus application, which is the whole point: one Rails codebase instead of a Python API and a separate Next.js app. The redirect map is drawn from the Next.js routes, every product, collection and content URL mapped to a 301 on the new shop and tested before launch. A three week parallel run on a staging address, a catalogue freeze through it, two rehearsals of the final import, and a cutover on a quiet Tuesday morning outside roasting season. The old Saleor environment stays up and untouched for thirty days as the fallback, then one last export and cancellation.
The honest part: year one costs Shandon Roastery more than a year of Saleor Cloud Select would have. What she gets for it is a single owned Rails application, no monthly Cloud subscription and no overage fee on growth, and one person to ring. For a shop her size, that trade is worth it. For a shop half her size with no subscription and a contented developer, it would not be, and I would tell her that too.
When you should not move
Stay on Saleor if the headless, GraphQL architecture is something you actively want and use: several storefronts, heavy use of the event model, a team fluent in it. Stay if your only grievance is the Cloud bill and the bill is bearable, because a migration carries a risk that a bearable bill does not. Stay if you cannot yet name the person on your side who understands the data, the variants and which customers are on the club, because without that person you get a tidy new shop full of wrong data. And never move in the weeks before your peak season.
Move when the shop is a single application pretending to be a platform team, when you want one accountable builder and the Rails ecosystem, and when the Saleor Cloud pricing has stopped matching the value for a shop your size. If you want the five year arithmetic behind that call, I work it through in the total cost of ownership of moving to Solidus, and I compare the main platforms honestly in Solidus against Shopify, Shopware, Magento and WooCommerce.
The close
Saleor is not a platform I steer people away from. It is a capable, open source, GraphQL native project, and if it suits your team it suits. The businesses I help off it are the ones for whom the fit has quietly come apart: a single shop bearing the weight of a composable architecture it does not need, an owner who wants one builder instead of two disciplines, a Cloud bill that no longer adds up. For them a custom Solidus store is less to run, easier to hire for, and wholly theirs.
If that sounds like your shop, bring the real picture to a free workshop, and the first two weeks of work are on me. I will tell you honestly whether a move pays off, and if Saleor is still the right home for you, I will say that instead.