Migrating away from Saleor to a custom Solidus store
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 starts a Saleor move
Saleor is a good piece of software, so the message I get about it reads differently from the one I get about a locked platform. It rarely says "we cannot get our data out" or "the vendor has us trapped". It tends to go more like this. We launched on Saleor two years ago because a developer set it up as a GraphQL store with a React storefront, it works, but the developer has moved on, hiring for Python and GraphQL and a separate front end is hard, and I want one person who owns the whole thing. Or: the Saleor Cloud bill has grown, and I am no longer sure the headless machinery earns its keep for a shop my size.
This is my honest answer for a business thinking about leaving Saleor for a custom shop on Solidus, the open source Ruby on Rails commerce framework I build on. I will be fair, because Saleor earns it. The code is genuinely 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 I will spend most of this article on what fit means here, what actually moves, and where the real work sits.
For the deep, platform independent detail, how customer accounts, catalogues, orders and saved cards move in general, I link to the data type guides in this series rather than repeat them. Start with the pillar, what moves and what does not.
What Saleor is, and who should stay on it
Saleor describes itself plainly. Its own project file calls it a headless ecommerce platform built with Python, GraphQL, Django and React, released under the BSD 3 clause licence.1 The repository front page calls it a GraphQL native, API only platform for composable commerce, and lists "headless and API only" and "GraphQL only" among its defining traits.2 The architecture overview says the engine is written in Python and that its API runs GraphQL over HTTP or message queues, with a lean core and a rich ecosystem of external applications around it.3
Two words in there matter more than the rest. "Headless" means Saleor ships no bundled shop front. You build the storefront yourself, usually 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 primitives that you assemble and extend with apps and webhooks. This is a deliberate, modern design, and it is genuinely good at what it is for.
So who should stay on Saleor? A team that wants composable, event driven, GraphQL commerce, that runs several storefronts or sales channels off one back end, that has Python and front end engineers or can hire them, and that is content to own that architecture. If Saleor fits your business and your people are productive in it, moving to Solidus is a sideways step with a cost and no prize. I would say so in the workshop. If you are only weighing modern open source options against each other, that is a comparison exercise, not a migration, and moving off Medusa sits in the same bracket.
Who outgrows it is the opposite profile. A single shop that does not need the headless split. An owner who wants one accountable builder rather than a Python back end, a React front end, and whoever keeps the two in step. A business that would rather live in the Rails and Solidus ecosystem. And a shop on Saleor Cloud that has looked hard at the bill.
What you own, and what is actually locked
Here I have to be careful, because the usual migration argument does not apply. Run the self hosted edition and you own all of it: the source, the PostgreSQL database and every row in it. The BSD licence even lets you keep your own modifications private, with no duty to publish them.4 Run Saleor Cloud and you still own your data and can leave. What you do not own is the running infrastructure, and the GraphQL API is your door in and out. Saleor's own position is that Cloud is the best way to run the product and the most cost effective once total cost of ownership is counted,4 and for many teams that is a fair claim.
None of that is a trap. If someone has told you that leaving Saleor means losing your data, they are wrong, and who actually owns your business data is worth reading before you believe any vendor 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 if you are on it, and the ordinary third party ties that every platform has, chiefly the payment gateway that holds your card tokens and whatever runs your subscriptions. I will take those one at a time.
The export and API reality
Saleor is API first, and the API is GraphQL, with no REST interface to fall back on.2 That shapes every extract you will do.
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 set, or a list of IDs, with the fields and column order you choose, and the finished file arrives as a download link by email.5 It covers products and variants, including attributes, stock quantities and per channel prices, and it is the cleanest single tool in the box. It does not export customers or orders.
Those you pull through the GraphQL API with scripted queries. Three limits govern how. 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 counted from the number of objects you request, not the number returned, and the server rejects anything over its ceiling, reporting the cost and the limit back in each response.6 And on rate limiting the picture splits: free Saleor Cloud sandboxes allow 120 requests a minute and paid sandboxes 2,000, over which the API returns HTTP 429, while production Cloud environments and self hosted deployments have no fixed rate limit, though production may still throttle traffic that degrades the service.6 In practice a migration from Cloud is a careful, paced crawl of the API, written once and rerun until it is boring.
If you self host, you have a shorter path as well: direct access to the PostgreSQL database, which is the quickest way to move 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 whole toolkit.
One thing never comes across in usable form, on Saleor or anywhere else: passwords. They are stored hashed, so customers set a new one on their first visit to the new shop. That is a campaign to plan, not a technical hurdle, and the customer accounts and addresses guide covers how to run it without filling your inbox on cutover day.
The honest wedge: one application instead of two
Headless is a feature, not a fault. It is also the heart of the matter for a smaller shop. On Saleor you run, at a minimum, the Python engine, a storefront application you built and maintain, and the dashboard, with apps and webhooks around them for payments and anything else.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 serving several channels, that separation pays for itself. For a single shop, it is a lot of moving parts to keep in step, and the day the developer who understood both leaves is the day it starts to hurt.
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 implies.7 You can still go headless when you need to: headless and API first Solidus shows how the same shop can feed a mobile app or a second storefront later. The difference is that you are not forced into that 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 data argument, is why a certain kind of Saleor shop is better off on Solidus.
Payments, saved cards and the gateway
Saleor does not process payments itself. It integrates with gateways such as Adyen through apps and transaction webhooks, and the card data and reusable tokens sit with the gateway, not inside Saleor.85 That is good news for a move. The best case removes the hardest question entirely: 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 exactly where they are.
If instead you are changing gateway as part of the move, saved cards travel only between providers certified at PCI DSS Level 1, and even then the export is cards alone, not the subscriptions or the payment history attached to them.9 This is the item to raise in the first conversation, not the last week, and the payment tokens and saved cards guide sets out the questions to ask 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 consequence for a move is that "what actually runs the subscriptions, and where do the schedules and the mandates live" is a question you answer before you plan anything else, because an active subscription is the hardest object in any migration. The subscriptions and recurring payments guide walks through the cases, from a clean cutover to a slow transition 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 routes your React or Next.js app uses for products, categories and content are the ones carrying your rankings and your inbound links, and they have to land somewhere sensible on the new shop. The rule is the same as for any move: list every old URL that took a visit or a link in the last year, map each one to its new address, and serve a permanent redirect, a 301 in almost every case, pointing straight at the final destination rather than through a chain. Keep the redirects for at least a year, 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 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 UK GDPR.11 A migration does not need 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: Lanes Roastery, Brighton
Lanes Roastery (lanesroastery.example) is an invented Brighton coffee brand turning over about £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, which is roughly 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 worked well.12 The problem is people, not the platform. That developer now works on their own and is hard to book, the owner cannot find one person who is 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 internal 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 takes the hardest item off the table. Subscriptions: the coffee club runs through an app wired into Saleor, so before anything else I establish where the schedules and the Stripe mandates actually live, and plan to move the club as its own small project, very possibly with both systems running for one billing cycle so no renewal is dropped.
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 paced crawl that follows cursors 100 records at a time and stays well inside the Select plan's limits,6 brought in as read only history for the last three years with the full export archived. Passwords are not touched, and every account is recreated in the new shop ready to activate, and a service message before cutover tells club members and customers what to do on their first visit.
The storefront is rebuilt as part of the Solidus application, which is the point of the exercise: 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 during it, two rehearsals of the final import, and a cutover on a quiet Tuesday morning out of 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 Lanes 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 call. For a shop her size, that trade is worth it. For a shop half her size with no subscription and a happy 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 that is fluent in it. Stay if your only complaint is the Cloud bill and the bill is bearable, because a migration carries 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 decision, 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 warn people away from. It is a capable, open source, GraphQL native project, and if it fits your team it fits. The businesses I help off it are the ones for whom the fit has quietly come apart: a single shop carrying 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 entirely 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.
Footnotes
-
Saleor, pyproject.toml (project description "headless e-commerce platform built with Python, GraphQL, Django, and React" and
license = "BSD-3-Clause"), GitHub, accessed 14 November 2026, https://github.com/saleor/saleor/blob/main/pyproject.toml ↩ -
Saleor, repository README (GraphQL native, API only platform for composable commerce, "Headless and API only", "GraphQL only"), GitHub, accessed 14 November 2026, https://github.com/saleor/saleor ↩ ↩2
-
Saleor documentation, Architecture (engine written in Python, GraphQL over HTTP or message queues, lean core and external applications), accessed 14 November 2026, https://docs.saleor.io/overview/architecture ↩ ↩2
-
Saleor documentation, Open source (BSD licence lets you keep modifications private, Saleor Cloud described as the best and most cost effective way to run Saleor), accessed 14 November 2026, https://docs.saleor.io/overview/why-saleor/open-source ↩ ↩2
-
Saleor documentation, Exporting products (CSV or XLSX, scope ALL, FILTER or IDS, chosen fields, download link emailed), accessed 14 November 2026, https://docs.saleor.io/developer/export/export-products ↩ ↩2 ↩3
-
Saleor documentation, Usage limits (cost counted from objects requested, pagination capped at 100 items per page, free sandboxes 120 requests a minute and paid 2,000 with HTTP 429, production Cloud and self hosted have no fixed rate limit), accessed 14 November 2026, https://docs.saleor.io/api-usage/usage-limits ↩ ↩2 ↩3 ↩4
-
Solidus, solidusio/solidus repository (open source Rails ecommerce under the BSD 3 clause licence, ships a REST API), GitHub, accessed 14 November 2026, https://github.com/solidusio/solidus ↩
-
Saleor documentation, Webhooks overview (synchronous and asynchronous events, Local and External Apps, transaction events for payments), accessed 14 November 2026, https://docs.saleor.io/developer/extending/webhooks/overview ↩
-
Stripe documentation, Request a payment data export (card data exported only to a processor certified at PCI DSS Level 1, excluding subscriptions and payment history), accessed 14 November 2026, https://docs.stripe.com/get-started/data-migrations/pan-export ↩
-
Google Search Central, Site moves with URL changes (map every URL, use 301 or 308 redirects, keep them for at least a year), accessed 14 November 2026, https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes ↩
-
UK GDPR, Article 28 (Processor), legislation.gov.uk, https://www.legislation.gov.uk/eur/2016/679/article/28 ↩
-
Saleor, Cloud pricing (Select at USD 1,599 a month up to USD 200,000 GMV with a 0.8% fee on orders above it, Volume at USD 3,999, and a Forever Free sandbox), accessed 14 November 2026, https://saleor.io/pricing ↩
-
Saleor documentation, ProductVariant API reference (variants with SKU, attributes, stock records and per channel price listings), accessed 14 November 2026, https://docs.saleor.io/api-reference/products/objects/product-variant ↩