Migrating away from OpenCart to a custom Solidus store
OpenCart is one of the easier shops to leave, because it is open source and self hosted and you already own the database. The hard part is never the export. It is untangling the tower of paid extensions, the painful version upgrades and the business rules hidden in modifications, and rebuilding all of that as one owned, tested application. In this article I walk through the move off OpenCart onto a custom Solidus store, specifically for this platform: what you own, what is locked, how the export and API really work, where the traps are, and the honest plan. For the deep detail of how each kind of data travels, I link to the guides that own it.
What OpenCart is, and who outgrows it
OpenCart is a free, open source shop built in PHP that you host yourself. You download it, put it on your own server, point it at a MySQL or MariaDB database, and it is yours to run.1 It is released under version 3 of the GNU General Public License, so there is no licence fee and no revenue share, and the source code is open for you or any developer to read and change.2 For a lean shop that is a strong position to be in, and I will say plainly: if your OpenCart store is small, stable and inexpensive to keep running, you should probably stay on it. This article is not for you.
It is for the shop that has outgrown it. The pattern is always the same. The catalogue grew, the trade side grew, and the store became a tower of paid extensions that all have to agree with each other. Every one of them wants its own licence renewed. A major version is out, the theme was bought for the old version and does not run on the new one, and half the extension authors have not updated their work or want paying again. Somewhere in the store a developer who left two years ago hid an important rule inside a modification file, and nobody is quite sure what it does. The shop still works, but changing anything feels like defusing a bomb.
If that is where you are, the good news is that OpenCart is one of the easier platforms to leave, because you already own the data. The hard part is not the export. It is untangling what the extensions and modifications were really doing, and rebuilding that as one owned, tested application. I build that application on Solidus, an open source shop framework on Ruby on Rails, and I run the move. The result belongs to you. This article is the honest shape of that move, told specifically for OpenCart. For the deep, platform independent detail of how each kind of data travels, I link out to the guides that own it rather than repeat them here, starting with the pillar, what moves and what does not.
What you own, and what is locked
Because OpenCart is self hosted, the single most important fact about leaving it is in your favour: the database is yours. Everything the shop knows lives in tables you can read directly, with a prefix like oc_ in front of names such as oc_product, oc_customer, oc_order and oc_seo_url. A plain database dump with mysqldump gives you the lot, and from there the mapping into a new model is ordinary, careful work rather than a fight for access. Compare that with a hosted platform, where you get only the exports the vendor chooses to give you, and you can see why open source shops are kinder to leave.
So what is locked is not the data. It is the behaviour built around the data: the payment and shipping logic that each extension holds in its own way, the business rules hidden in modifications, the theme written for one version of OpenCart, and the integrations wired to this particular install. None of that travels. It has to be understood and rebuilt. The table below is the honest division.
| What | How it travels | Where it goes |
|---|---|---|
| Products, variants, options, attributes, prices, images, categories, stock | Clean, through direct database access or the export tool, as a mapping exercise | The Solidus product model, see products and catalogue data |
| Customer accounts and addresses | Clean, but passwords are hashed and cannot be reused | Rebuilt with a reset or verify at first login, see customer accounts |
| Order and purchase history | As records, for reference and customer service | A read only history in the new shop |
| SEO keywords and URLs | As a list to map, not to copy | A redirect table in the new shop |
| Payment configuration and saved cards | Not portable, each extension stores it differently | Rebuilt around your own gateway account, see payment tokens |
| Theme, modifications and integrations | Do not travel at all | Rebuilt as owned, tested code |
The export and API reality
OpenCart gives you three honest ways to get your data out, and it is worth being precise about what each one is, because the marketing around migration tools blurs them.
The first is direct database access, and it is the strongest. You own the server and the database, so a full dump is always available to you. For a large catalogue or a complex order table this is the route I actually use, because nothing is hidden and nothing is summarised away.
The second is the export and import tool. People often believe this ships inside OpenCart. It does not. The widely used Export/Import Tool is a community extension, maintained for the project and distributed through the OpenCart marketplace, and you install it yourself.3 It does a real job: a bulk export of categories, products, options, attributes, filters and customers into a spreadsheet you can edit offline and re import. The import can run in two modes, one that adds and updates against what is already there, and one that deletes all the old data first and replaces it. Two cautions matter. Its memory needs are high, and on basic shared hosting the author advises exporting no more than a few thousand products at a time and working in batches.3 And the spreadsheet is a convenience layer, not the whole truth: anything a custom field or an extension stored outside the standard tables will not be in it. For a shop of any size I treat the spreadsheet as a starting point and reconcile it against the database.
The third is the API, and here expectations need managing. OpenCart has a built in API, configured under the system users, where you create a credential with a username, a generated key and a list of allowed IP addresses, and switch it on or off.4 What the documentation describes is an interface for trusted applications to talk to your store, with an audit history of calls, not a full read interface over your whole catalogue. There is no documented endpoint that simply lists every product, customer and order for you. The built in API was built around cart and order operations for the storefront and companion apps, and a true REST interface over the data generally means adding a further extension. OpenCart itself imposes no published rate limit on the built in API; any ceiling you hit is your host's, not the platform's.4 The practical conclusion is simple: on OpenCart you migrate from the database, and you treat the API as a supporting actor, not the star.
Passwords never move, and that is fine
No password comes across in readable form, from OpenCart or from any competent platform, because OpenCart never stores the password itself. The current version hashes each password with PHP's own password_hash function using the default algorithm, which today is bcrypt, and writes only that hash.5 Older OpenCart installs used a salted, repeatedly hashed SHA1 scheme instead, with a short random salt stored beside the hash.6 Either way the stored value is one directional. It cannot be turned back into the password, so there is nothing to carry over that a customer could log in with.
This is a feature, not a loss, and the plan around it is the same one the customer accounts guide sets out in full. Every account, with its name, addresses and order history, is created in the new shop. On the first visit the customer either sets a new password through a one time link or, if you keep the old hashes, has the old hash verified once and then silently replaced with the new shop's format so they never notice. Whichever you choose, nobody ever sees a password in the clear, and the account the customer rebuilds is attached to all of their history.
The extension tower is the real reason to leave
Almost nobody leaves OpenCart because the data is trapped. They leave because of what sits on top of it. A working OpenCart shop of any ambition is rarely core OpenCart. It is core OpenCart plus twenty or thirty paid extensions: a better search, layered filters, a trade pricing module, abandoned basket emails, a reviews system, a returns portal, an accounting connector, a feed for marketplaces, and a payment extension or two. Each one is a separate purchase from a separate author, on its own release schedule and its own quality. They have to work together, and they have to keep working together every time one of them updates. When they disagree, the shop breaks in ways that are hard to trace, because the fault is in the space between two extensions that neither author owns.
On top of that sits the upgrade question, which on OpenCart is sharper than on most platforms. The jump between major versions, from the 1.5 line to 2, from 2 to 3, from 3 to 4, is less an upgrade than a rebuild. Themes are written against a specific version and its template system, so a theme bought for one line does not simply run on the next. Extensions have to be reissued by their authors for the new version, and many never are, or are, but only to customers who pay again. So a shop that wants to stay current faces, every few years, a project that costs nearly as much as a fresh build but delivers nothing new to show for it. That is the treadmill. My case for a custom Solidus store is not that Rails is fashionable. It is that you replace a tower of other people's extensions, each a dependency you do not control, with one application that is yours, that has tests proving it behaves, and that one developer who knows it can maintain and extend without asking anyone's permission.
Modifications hide your business logic
OpenCart has a clever system for changing how the shop behaves without editing the core files, called OCMOD, with an older third party ancestor called vQmod that many live shops still carry. A modification is an XML instruction that says, in effect, find this line in that file and change it, and the system applies the change to a copy at runtime so the original is left alone.7 It is a sensible idea, and it is also where business logic goes to hide.
The trap is that over years, the real rules of your shop migrate into these modification files. The way trade customers are priced, the odd rounding your accountant insists on, the extra field on the order, the way a particular courier's label is produced: a developer, often one long gone, solved each of these with a small modification, and the knowledge left with them. When you migrate, those files are the single most valuable and most dangerous thing to understand, because they are the difference between the shop you think you have and the shop you actually have. The first serious job in any OpenCart migration I run is to read every modification and write down, in plain English, what each one really does. That document, not the data export, is usually where the surprises live.
SEO URLs and the redirect map
OpenCart has two ways of forming the address of a page. Out of the box it uses query strings, so a product sits at something like index.php?route=product/product&product_id=42. With SEO URLs switched on, each product, category and information page is instead given a keyword, which has to be unique across the whole shop, and the server is configured to rewrite the friendly address to the real route.8 Those keywords are the URLs your customers have bookmarked and that search engines have indexed, and if you have run the shop for years they carry real ranking.
The move to a new shop is where that value is most often thrown away, and it has nothing to do with OpenCart specifically and everything to do with discipline. Every address that received a visit or a link in the last year has to be mapped to its new home with a permanent redirect, and the redirect has to point straight at the final page, not through a chain. The full method, and why most ranking loss in a migration comes from missed redirects rather than from the move itself, is in the products and catalogue guide. On OpenCart the one platform specific note is that your keyword list lives in a database table you can read directly, so building the first draft of the redirect map is a query, not a crawl. On the shops I build the redirects live in the application itself as an editable table, so they survive every future deploy and your own staff can add one when they spot a stray.
Payments and saved cards
Payments are where an OpenCart move stops being tidy. In OpenCart each gateway is a separate payment extension, and each stores its configuration, and any reference to a saved card, in its own way. There is no single, portable payment vault to hand over. What actually matters is who holds the card data, and the answer is never OpenCart: it is your payment provider. If your shop already charges cards through its own Stripe or similar account, the saved cards belong to that account, and the new Solidus shop can connect to the same account so that the cards simply stay where they are and nothing is lost. If instead the cards sit inside a provider you reached only through an OpenCart extension, moving them means a provider to provider transfer that the receiving processor will only accept from another holder certified to the top level of the card security standard, and that never includes the subscriptions or the payment history alongside the cards.
This is the single most important thing to settle first, not last, and the payment tokens guide walks through every case. If you take nothing else from this section, take this: decide your payment provider before you write a line of the new shop, because that one decision determines whether returning customers keep their saved cards or have to enter them again. If the subject makes you nervous, the hidden dangers of switching payment gateways is the cautionary version.
Subscriptions and recurring payments
If your OpenCart shop sells anything on a repeating basis, treat it as the hardest part of the whole move and raise it on day one. OpenCart can handle recurring products, but the actual charging depends on the specific payment extension supporting it, and the mandate that lets you charge a customer again lives with the gateway, not in OpenCart. That means a live subscription cannot simply be exported as a row and replayed in the new shop. Whether it can move at all depends on your gateway and often needs its cooperation, and sometimes the honest answer is that existing subscribers have to re authorise. The subscriptions guide sets out the options and the questions to ask your provider. The rule is the same as for cards: surface it first, because the answer shapes everything else.
A worked example
Let me make this concrete with an invented shop. Aire Valley Workwear (airevalleyworkwear.example) is a Leeds business selling boots, overalls and safety gear, with a growing trade side supplying building firms on account. It turns over about £1.4 million online, carries roughly 6,000 products once sizes and colours are counted, and has been on OpenCart 3 for five years. Over that time it has bought twenty two paid extensions and accumulated a dozen modifications. The trade pricing, the way account customers see prices without VAT, and a custom field on orders for the site a delivery goes to are all done through modifications written by a developer who moved on.
The owner's problem is not that the shop is broken. It is that it has become frightening to touch. OpenCart 4 is out, the theme was bought for 3 and the author has not reissued it, four of the extensions are abandoned, and the quote to get everything working on the new version is close to the cost of starting fresh, for no new capability. She has decided to stop renting other people's extensions and own the shop instead.
Here is how the move goes. The clean part comes first and reassures everyone: a full database dump, and from it the 6,000 products with their sizes, colours, prices, stock and images map onto the Solidus catalogue over a couple of weeks of careful matching. The customer records, including the trade accounts, come across with their addresses and order history, passwords excepted. The order history is brought in as read only reference, three years deep, with the older records kept in the archived export. The SEO keywords are read straight from the database into the first draft of the redirect map, about 7,000 rows that one person then checks.
Then the hard parts, which were raised in week one, not week ten. The trade pricing and the without VAT display, found by reading the modifications, become real, tested features of the new shop rather than patches. The order field for the delivery site is rebuilt properly. Payments are the pivot: the shop already uses its own Stripe account, so the new Solidus store connects to that same account and the trade customers' saved cards stay valid, which turns the scariest part into the easiest. There are no subscriptions, so that question is closed quickly. Fourteen weeks after the first workshop, Aire Valley cuts over on a quiet Tuesday morning, keeps the old OpenCart install running untouched for thirty days as a fallback, and only then cancels it. A year on, the shop is one maintained application with tests, no extension renewals, and the trade rules written down where the next person can read them.
The honest move plan
Stripped to its bones, leaving OpenCart for a custom Solidus store runs like this. First, discovery: read every modification and write down what it does, list the extensions and what each one is really for, pick the payment provider, and name the one person inside the business who owns the data. Second, the build: stand up the Solidus shop, write the import scripts, and run them again and again against a copy of the real database until the import is boring. Third, map the catalogue and the customers, and turn the hidden modification logic into tested features. Fourth, build the redirect map from the keyword table and check every row. Fifth, a parallel run of a few weeks with the catalogue frozen, rehearsing the final import twice. Sixth, cut over on a quiet weekday morning, place a real test order on every payment method, check the top redirects by hand, and keep the old shop as a fallback for thirty days before cancelling anything.
Through all of it the principle is the one in the pillar: move the shop as it is, make it stable, and only then improve it. Turning a migration into a redesign at the same time doubles the risk and makes it impossible to tell which change caused a dip.
When you should stay on OpenCart
I would rather lose the work than sell you a move you do not need, so here is when to stay. Stay if your OpenCart shop is small, the extensions you depend on are few and well maintained, and the bill is bearable. Stay if nothing is actually blocking you and the only complaint is a vague feeling that the software is old. Stay if you cannot name the person in your business who understands the data, the trade rules and why the old product codes have the suffixes they do, because without that person any migration, to any platform, produces a tidy new shop full of wrong data.
Move when the extension tower has become a tax and a risk, when the next major version upgrade costs as much as a fresh start for nothing new, when the rules that run your business are trapped in modifications nobody can read, and when you want a shop you own outright and can have tested properly. For the money side of that decision, the five year cost of moving to Solidus works the numbers, the platform comparison sets OpenCart beside the alternatives, and who actually owns your business data is the principle underneath it all. If you are weighing other open source shops in the same breath, I have written the same honest guide for leaving WooCommerce and for leaving PrestaShop. Solidus itself is open source under the BSD licence, so the shop I build for you carries no licence fee and no lock in of its own.9
The workshop
If you run an OpenCart shop and you are not sure whether you have outgrown it, bring it to a free workshop and the first two weeks of work are on me. Bring your extension list, your renewal invoices, and whatever you know about the modifications. Together we read what the shop actually does, work out what moves cleanly and what has to be rebuilt, flag the payment and subscription questions first, and I tell you honestly whether a move pays off for you. Sometimes it does not, and I will say so.
Footnotes
-
OpenCart documentation, System Requirements (PHP 8.0 or later, required PHP libraries, MySQL or MariaDB via the MySQLi or PDO driver, PostgreSQL, Apache recommended), checked 14 November 2026, https://docs.opencart.com/getting-started/system-requirements ↩
-
OpenCart source repository, licensed under the GNU General Public License version 3, GitHub, checked 14 November 2026, https://github.com/opencart/opencart ↩
-
OpenCart marketplace, Export/Import Tool (a community maintained extension by JNeuhoff, bulk export and import of categories, products, options, attributes, filters and customers to a spreadsheet, incremental or full replace import, high memory needs, a few thousand products per batch on basic shared hosting), checked 14 November 2026, https://www.opencart.com/index.php?route=marketplace/extension/info&extension_id=17 ↩ ↩2
-
OpenCart documentation, System users API (API credential with username, generated key, allowed IP list, status and an audit history; built for trusted application access, not documented as a full catalogue read interface; no platform imposed rate limit stated), checked 14 November 2026, https://docs.opencart.com/admin-interface/system/users/api ↩ ↩2
-
OpenCart source,
catalog/model/account/customer.php(customer passwords hashed with PHP password_hash using PASSWORD_DEFAULT), GitHub master branch, checked 14 November 2026, https://github.com/opencart/opencart/blob/master/upload/catalog/model/account/customer.php ↩ -
OpenCart issue 1269, legacy password hashing used a short random salt with repeatedly applied SHA1, GitHub, checked 14 November 2026, https://github.com/opencart/opencart/issues/1269 ↩
-
OpenCart wiki, Modification System (OCMOD changes a store through XML instructions applied to copies of core files, so the originals are untouched), GitHub, checked 14 November 2026, https://github.com/opencart/opencart/wiki/Modification-System ↩
-
OpenCart documentation, SEO URL (default route based addresses such as index.php?route=product/product, replaced by a unique keyword per product, category and information page, with server rewriting required or friendly URLs return 404), checked 14 November 2026, https://docs.opencart.com/design/seo-url ↩
-
Solidus source repository, the Solidus ecommerce framework under the BSD 3 clause licence, GitHub, checked 14 November 2026, https://github.com/solidusio/solidus ↩