PrestaShop 9.1.0 went stable on 23 March 2026, two and a half weeks after RC1. We have been running it on our own dev infrastructure since the betas, and we have migrated a chunk of our 151 modules through it. Below is the version of the release notes we wish someone had written for us — what actually changed, what is hype, and what we have hit in practice.
Update — 24 March 2026: 9.1.0 is officially out. Hummingbird 2.0 is the new default theme, multi-carrier shipping and the redesigned discount engine both ship behind feature flags, and PHP 8.1 through 8.5 is supported. Grab it from prestashop.com/versions or the GitHub release. Our own modules: we have run them all through a 9.1 install and the obvious things work; we will keep flagging edge cases as we find them.
If you have been parked on 1.7 or 8.x waiting for the right moment to jump, 9.1 is a defensible target. It is also not magic. Here is what the changelog leaves out.
Hummingbird 2.0 — finally the default, with caveats
The headline change: Hummingbird is the default theme on fresh installs. The original Hummingbird shipped with 9.0 as an opt-in modern theme; 2.0 is a real overhaul, not a coat of paint.
- Bootstrap 5.3.3 instead of the alpha used in Hummingbird 1.x. That gets you a stable utility API, working dark mode hooks, and CSS custom properties you can actually rely on in a child theme.
- EAA accessibility work — the team is quoting "over 95%" compliance against the European Accessibility Act (in force since June 2025). Better ARIA, better contrast, keyboard navigation that actually works. Worth saying out loud: 95% is not 100%, and we have already had to patch a couple of focus-state bugs in our own checkout overlays. Test before you ship to a regulated buyer.
- jQuery is deprecated, not removed. It is still in the bundle, marked for the chop in PrestaShop 10. If you are writing new module JS, write it vanilla. We did the conversion across our front-office modules last year and have not missed it once.
- New JS hook attributes —
data-ps-ref,data-ps-action,data-ps-targetreplace ad-hoc CSS selectors as the recommended JS binding surface. The point is that designers can rename classes without breaking module scripts. We like this change. - Hook delta:
displayOrderDetailanddisplayModalContentare new.displaySearchis gone — if your module registered on it, you need a replacement.
For the child theme work itself, we have written it up separately: Child Themes guide. Short version — start from the Hummingbird 2.0 starter, do not fork the parent.
Hummingbird 1.x → 2.0: what bites
If you already shipped a child theme against Hummingbird 1.x, this is where you spend your migration day:
- Bootstrap 5.3 class renames.
ml-*/mr-*→ms-*/me-*.data-toggle→data-bs-toggle..custom-control→.form-check. Grep your child theme and your module templates. We found these in modules we had not touched in two years. - JS selectors. Class-based selectors like
.product-add-to-cartstill work, but the convention is moving todata-ps-ref. Migrate gradually — there is no flag-day deadline yet. - Colour overrides. Bootstrap 5.3 compiles colour values into component-local CSS custom properties. Overriding the global
:roottoken is not enough for things like.btn-primary— you need.btn-primary { --bs-btn-bg: #yourcolor; }. The first thing every "the brand colour did not apply" support ticket needs.
Multi-carrier shipping — the feature merchants have asked for since 1.5
This is the one. One order can now ship via multiple carriers, with independent tracking and statuses per shipment.
Up to and including 9.0, one order meant one carrier. Sell a 200kg shower tray plus a tube of silicone and the merchant had to either split the order by hand, build a custom module, or eat the difference. Every wetroom client we have wanted this for years.
9.1 introduces shipment-level carrier assignment:
- Split an order into multiple shipments, each with its own carrier and tracking
- Merge shipments back together if the warehouse changes plan
- Track each shipment independently through the order workflow
- Per-shipment delivery dates and statuses
Two important caveats. First, this ships behind a feature flag — opt in, do not assume it. Second, the API is explicitly marked as "may evolve" by the core team, so if you write integration code against it today, expect to revisit it before 10.0. We are not yet wiring it into our shipping modules in production — we are waiting for at least one minor release of the API to settle.
If you sell a mixed catalogue — furniture plus accessories, equipment plus consumables, anything where DHL handles the small stuff and a pallet courier handles the rest — this is the upgrade pretext.
The new discount system
The legacy cart rule engine has a successor. It is also behind a feature flag and off by default. The new model splits discounts into four explicit types:
- Catalog discounts — applied to products before the cart
- Cart discounts — applied at checkout based on conditions
- Free shipping — a discount type of its own, not a checkbox on a cart rule
- Free gift — products added automatically
The legacy cart rules keep working — nothing breaks on upgrade. The new system is faster (we have seen one shop with 600 cart rules where the admin page was unusable; the new model handles it without complaint) and easier to reason about. Reporting also gets clearer: you can finally separate "revenue lost to free shipping" from "revenue lost to percentage discounts" without parsing a single monolithic table.
We have not yet migrated any client off legacy cart rules in anger. Behind a feature flag means "test on staging, do not flip in production without a rollback plan."
Developer-side changes worth knowing
The bullets below are the ones we actually care about as module authors, not the full changelog:
- New hooks:
actionModuleEnable,actionModuleDisable,actionModuleUpgradeAfter,actionConfigurationUpdateValueBefore.actionModuleUpgradeAfteris the one we have been waiting for — it lets us run post-upgrade migrations reliably without bolting onto our ownupgrade-*.phpordering. - New CLI commands:
prestashop:thumbnails:regenerate,prestashop:search:index,prestashop:translation:export-module. The thumbnails command alone saves us an hour every time we deploy a catalogue refresh. - Doctrine auto-mapping improvements for module entities — less services.yml boilerplate.
- PHP 8.1–8.4 officially supported, 8.5 being tested. We run our dev container on 8.4 and have not hit anything.
- Updated VAT rates for Estonia and Romania.
- D3 and NVD3 updated — if you have custom dashboard widgets, regression-test them.
- Classic theme goes to 3.1.1 for shops that have not moved.
Why 9.1 is a sensible migration target
The question we get from clients on every call: "I am on 1.6 / 1.7 / 8.x — upgrade now, or wait?" Our answer for the past year has been "wait for 9.1." That answer is now "go."
From PrestaShop 1.6
1.6 has been end-of-life since October 2023. No security patches, no compatibility work, and PHP 7.x is dead on most hosts. Every month adds risk and migration cost.
Reality check on effort: a 1.6 → 9.1 migration is a rebuild, not an upgrade. The data (products, customers, orders) migrates. The theme does not — plan on a Hummingbird 2.0 child theme from scratch. Most modules need replacements. Two to six weeks of work for a non-trivial shop, mostly testing, not the upgrade itself.
The shape of the job:
- Stand up a clean 9.1 install on staging
- Export catalogue, customers, orders from the 1.6 source
- Import via the official tools or a direct DB migration script — we usually script it
- Install and test every module individually, not as a batch
- Build the child theme on Hummingbird 2.0
- Plan 301s for every URL that changes shape
- Test every checkout path — payment gateway, shipping, transactional email
- Cut DNS in a low-traffic window
From PrestaShop 1.7
1.7 was the transitional release — half legacy, half Symfony. 9.1 finishes the migration 1.7 started: admin is Symfony end-to-end, the API surface is modern, the default theme is finally a proper modern responsive theme.
Module compatibility is reasonable. Well-maintained modules already work on the 1.7 → 9.x path. Use the Update Assistant (the old autoupgrade) — but only against a staging copy. We have seen the Update Assistant fail mid-run on real shops because of orphan DB rows or a custom override; if that happens in production, you have downtime instead of a debug session.
Things that hit during 1.7 → 9.1:
- Override files in
override/classes/are the single biggest source of upgrade pain. Many will conflict with the new architecture. Review every one and replace with a hook where possible. - Removed APIs.
Tools::displayPrice()is gone.AdminController::ajaxDie()is gone. If your custom modules call them directly, they will fatal. We wrap deprecated APIs in ourprestashop-compatpackage — if you maintain your own modules, the same pattern is worth copying. - Classic-based themes from 1.7 mostly work on 9.x with visual quirks. Hummingbird 1.x child themes need the Bootstrap 5.3 rename pass.
- PHP. 9.1 requires 8.1 minimum. If your host is still on 7.4 or 8.0, that is the first migration, before you touch PrestaShop.
From PrestaShop 8.x
This is the easy one. The big jump was 8 → 9.0 (Symfony 4.4 → 6.4, new admin API). 9.0 → 9.1 is incremental. If your modules already run on 9.0, they should run on 9.1 with light regression testing.
The reasons to do it: Hummingbird 2.0 beats Classic for new builds, multi-carrier fixes a real operational problem, and you stay on the maintained branch.
Where to look after the upgrade: any admin customisation (the admin API moved in 9.0), modules in the order pipeline (multi-carrier touches the order object model), and dashboard widgets (D3/NVD3 update).
The long-term view
PrestaShop 10 is the next destination. jQuery goes away entirely. The admin keeps modernising. The native one-page checkout (the feature merchants have wanted for a decade) has its first code merged and is targeted for a future minor. B2B work is in flight in the core.
9.1 on Symfony 6.4 LTS is the version with the longest support runway available today. Staying on 1.6 or 1.7 means staying on something already unsupported.
Migration checklist
Wherever you are starting from, the order of operations is roughly the same:
- Audit. List every module, every theme customisation, every override, every external integration (payment, ERP, shipping API).
- Module compatibility pass. For each module, confirm 9.x support with the developer or in the changelog. Replace the unsupported ones before the upgrade run, not after.
- Staging environment. Clone production database and files to a separate server. Production is not a test environment.
- PHP first. 9.1 needs 8.1+. We default to 8.2 or 8.3 on client production stacks. 8.4 on our own dev rigs.
- Update Assistant for 1.7+ stores. Clean install plus data migration for 1.6.
- Test every checkout path. Every payment method, every shipping option, every transactional email. Place real test orders.
- Preserve URLs. 301 every URL that has changed shape. Watch Search Console for the first month.
- Reset OPcache the right way. Via a web request, not CLI — they have different pools. This is the cause of half the "white screen after deploy" tickets we see.
- Watch the first 48 hours. Error logs, conversion rate, page load times. Have a rollback plan documented.
What catches people
The recurring upgrade failures we see across client migrations, in order of frequency:
- Silent override failures. An override in
override/classes/Foo.phpstill loads instead of the core file even when the signature is wrong. PrestaShop will not always log it. Review and remove unused overrides before the upgrade, not after. - OPcache serving stale bytecode. You uploaded the new code, ran your tests via CLI, everything looked good — and the web pool is still serving the old build. Reset via a web-accessible PHP endpoint. We keep a fixed-name
opcache-reset.phpin every project for exactly this. - Custom columns on core tables. If you added columns to
ps_order,ps_product, etc., check them againstupgrade/sql/9.1.0.sql. Schema collisions take a shop down. - Payment webhooks pointing at the old URL. Domain change during migration? Update the webhook URL in Stripe, PayPal, Adyen, whichever you use. Missed webhooks mean missed order confirmations and unhappy customers.
- Cron paths. 9.x moved some entry points. Re-verify every scheduled task after upgrade.
- Email templates. The template engine moved on 9.x. Custom email templates from 1.7 do not always render correctly. Test every transactional email type, not just order confirmation.
Performance, honestly
9.1 on Symfony 6.4 is faster than older versions, but the reasons are not magic:
- Container compilation is cheaper in Symfony 6.4 than 4.4. Bootstrap time drops.
- Hummingbird 2.0 ships less CSS and JS than Classic. With jQuery deprecated, fresh installs carry a smaller JS payload than 1.7 ever did.
- PHP 8 JIT. Moving from 7.x to 8.x is where most of the "PrestaShop got faster" headline numbers actually come from. 10–30% typical for catalogue workloads.
- HTTP / Doctrine caching in Symfony 6.4 is a generation more mature than 4.4.
On our own dev container, a 5,000-product shop on 9.1 with Hummingbird 2.0 serves category pages at ~120ms TTFB. The same hardware running 1.7 with Classic was ~250ms. That number is a dev environment, not a production claim — your mileage will depend on hosting, modules, and configuration. But the direction is real.
About our modules
All 151 mypresta.rocks modules have been run through 9.1. We have been on 9.x internally since the betas. We ship one codebase that targets 1.7 through 9.1 — no separate forks, no version-specific ZIPs.
The pieces that matter for cross-version compatibility:
- Admin layer. We use a shared admin framework (our
prestashop-adminpackage) that wraps the Symfony shell so individual modules do not have to. Parent tabs, breadcrumbs, sidebar — all of it works under the 9.1 admin without per-module changes. - Translation. We use
$this->module->l()everywhere because it survives across versions. The removed$this->l()in admin controllers does not affect us. - Price formatting.
Tools::displayPrice()is removed in 9.0. We wrap it inMyPrestaRocks\Compat\PriceFormatter— calls the modern locale-based formatter on 8.x/9.x, falls back on 1.7. One helper, every PS version, noif (version_compare(...))littered through templates.
If you are planning a migration and want to test our stack on your data, grab a free 30-day demo of any module on staging. If you would rather have help, we also offer migration consulting.
FAQ
Can I skip 8 and go straight from 1.7 to 9.1?
Yes. The Update Assistant supports direct 1.7.x → 9.x. No intermediate 8.x step needed. Caveat: confirm every module is 9.x-compatible first.
Will my Classic theme still work on 9.1?
Yes. Classic is updated to 3.1.1 in 9.1 and remains fully supported — it just is not the default anymore. A Classic child theme should keep working with minor adjustments.
Is multi-carrier production-ready?
It ships behind a feature flag. PrestaShop considers it stable enough to use but reserves the right to change the API. If it is mission-critical, enable on staging, write integration tests, and be ready to revisit your code in 9.2.
Which PHP version?
8.2 or 8.3 for conservative production stacks. 8.1 is the floor. 8.4 and 8.5 are supported and we are running 8.4 on dev, but verify your whole module stack before pushing it to production.
How long does a typical migration take?
8.x → 9.1 with no exotic modules: an afternoon. 1.7 → 9.1 with 20+ modules: one to two weeks of testing. 1.6 → 9.1 with a theme rebuild: two to six weeks. The upgrade itself is fast — verifying every flow is what takes the time.
Wait or start preparing now?
Start now. 9.1.0 is stable. The next step is a staging upgrade — audit modules, test checkout, verify the theme, schedule the production cutover.
Bottom line
9.0 was the revolution: Symfony 6.4, new admin API, modern architecture. 9.1 is the version that makes 9.0 practical — a production-ready modern theme, the shipping model merchants have asked for since the 1.x days, and a discount engine that does not collapse under 600 cart rules.
Whatever version you are coming from, this is the one worth migrating to. The longer the wait, the wider the gap. If you have been holding for "the right release," 9.1 is it.
Comments
No comments yet. Be the first!
Be the first to ask a question or share useful feedback.
Leave a comment
Share a question, an installation detail, or feedback that could help another reader.