We have shipped PrestaShop modules across every version from 1.5 through 9.x — a decade that spans the smarty-and-overrides era, the 1.7 Symfony rewrite, the 8.x consolidation, and the 9.x present. That is long enough to stop guessing. What follows is not philosophy; it is the short list of engineering decisions that, in hindsight, separated the modules that survived ten years of upgrades from the ones that became support tickets. Every lesson here is tied to something specific in PrestaShop — a directory, a hook, a config key, a class — because vague advice ("write clean code") helps no one. So what's in it for you? If you build or buy modules, these are the things that actually decide whether your store stays stable through the next upgrade, and the questions worth asking before a module ever touches your shop.

Lesson 1: overrides are a debt you pay at upgrade time

PrestaShop ships an override system — drop a file in /override/classes/, /override/controllers/ or /override/modules/ and you change core behaviour without editing core files. It looks elegant. It is the single biggest source of the "my store broke after I installed a module" tickets we have ever handled.

The mechanics explain why. Overrides are compiled into PrestaShop's class index cache, whose location varies by version, for example cache/class_index.php on older 1.6-era installs. Two modules that both override Product or Cart cannot coexist — the second one to install simply fails, or worse, silently wins and breaks the first. There is no merge. And because the override is a frozen copy of a core class, the day you upgrade PrestaShop, your override still extends the old method signature while the rest of core has moved on. That is how a working store turns into a white screen after a minor version bump.

Our rule, learned early and never broken since: build with hooks, the module API, and (on 1.7+) Symfony services exclusively — never the override directory. If you cannot do a thing with a hook, the honest answer is usually that the thing should be done differently, not that you should reach for an override. When you evaluate a third-party module, the most useful question you can ask the vendor is "does this install anything in /override?" A "no" is worth more than any feature list. We unpack the broader engineering trade-offs of building on this platform in our honest look at why we chose PrestaShop.

Lesson 2: backward compatibility is a design decision, not a patch

A store running PrestaShop 1.6 spends real money and serves real customers. The temptation is to write only for the current version and tell everyone else to upgrade — but upgrades are expensive, risky projects that many merchants rationally defer for years. Abandoning them is abandoning a paying market.

The lesson is that compatibility has to be built from line one, because retrofitting it later is far harder. Concretely, that means:

  • Version-detect instead of assuming. A simple version_compare(_PS_VERSION_, '1.7.0.0', '>=') branch at the points where the API genuinely diverges (template engine, controller base classes, the gradual move from legacy ObjectModel/AdminController patterns toward Symfony controllers, services, forms and domain/CQRS code) costs a few lines and saves a fork.
  • Abstract the moving parts. The 1.6 → 1.7 jump changed how admin controllers, templates (.tpl Smarty vs Twig), and asset registration work. Wrapping those behind your own small helper means one code path, not two codebases.
  • Degrade gracefully. If a feature relies on something only 8.x+ exposes, detect its absence and fall back, rather than fatal-erroring on 1.6.

This is also a compatibility promise we make in copy and in code: our module code supports PHP 7.1+ where the installed PrestaShop version allows it; PrestaShop 9.x requires a modern PHP version, and the reason a module we wrote in 2016 still installs cleanly today is that the branches were there from the first commit. We wrote about the engineering reality of supporting that range in the challenges of PrestaShop module development.

Lesson 3: performance is a feature, and it has a budget

A module that adds 200ms to every page is not adding a feature — it is levying a tax the merchant pays on every visit, on every page, forever. The stores that stay fast are the ones whose modules respect a budget.

The PrestaShop-specific places this leaks, and how we hold the line:

  • Hooks that run on every page. A module hooked into displayHeader fires on most front-office page loads, and actionDispatcher fires early in request dispatching. If that hook does work it does not need to — a database query, a template render — on pages where the feature is irrelevant, exit early. The first line of the hook should check whether this page even needs it and return if not.
  • Assets loaded everywhere. Registering CSS/JS globally via registerJavascript()/registerStylesheet() in the actionFrontControllerSetMedia hook, instead of scoping them to the controllers that use them, bloats every page. Load assets where they are needed, nowhere else.
  • Uncached repeat queries. Results that do not change between requests belong in PrestaShop's Cache layer, not re-fetched on every load. Combine with the back-office caches (Advanced Parameters → Performance: Smarty cache, CCC for JS/CSS) for compounding gains.

Our working standard: a module should add under ~10ms to a page when it is not actively doing something on that page. That number is a target we hold ourselves to, not a guarantee about your specific store — your real overhead depends on your hosting, your other modules, and your data volume, and it is worth measuring with the Debug profiler (_PS_DEBUG_PROFILING_, alongside _PS_MODE_DEV_, on a staging copy) rather than trusting any vendor's claim, ours included.

Lesson 4: test on real stores, not fresh installs

A module that works on a clean PrestaShop with 10 demo products and no other modules has proven almost nothing. Real stores are 1,000+ products, 20–40 active modules, a custom or child theme, several languages, multi-shop in some cases, and years of accumulated order and customer data. That is where the surprises live.

The failures only a real environment surfaces are concrete and predictable: SQL that is fine on 200 rows and times out on 200,000; a hook that collides with another module's override (see Lesson 1); a translation that breaks because a string was hard-coded instead of run through the translation API; a multi-shop context where Shop::getContext() is not what you assumed. We keep restore-from-production staging copies precisely so customers do not become the test bed.

Lesson 5: the ecosystem decides your stability more than core does

Over ten years we have spent far more time diagnosing problems caused by other people's modules than by PrestaShop core. The math is unforgiving: a store's reliability is roughly the reliability of its weakest module, because one badly coded extension — an override conflict, a fatal in a hook, an unescaped query — can take an otherwise healthy store down.

Two practical conclusions came out of this. First, we write defensively: check for the conditions we expect, handle unexpected state instead of assuming other modules behaved, and never assume a hook payload is shaped the way the docs imply. Second — and this is the one that matters for store owners — module quality beats module quantity every time. Thirty cheap modules are thirty upgrade liabilities; five well-built ones are not. We made the full case for this in why module quality matters more than module quantity, the hidden bill behind "free" in the real cost of free modules, and how to tell good from bad before you buy in the PrestaShop Addons Marketplace buyer's guide.

Lesson 6: support tickets are your roadmap

The best features we ever shipped did not come from internal brainstorming — they came from the support inbox. The pattern recognition is the value: when several customers ask the same question, the documentation is unclear; when several request the same thing, the market is telling you what to build; when a bug shows up on one store, it is already latent on others, you just have not heard yet.

This is also why we sell with direct developer support — no middleman reseller layer. It is not only a customer benefit; it is our product-research channel. A vendor who outsources support loses the single richest signal about what their software actually needs.

Lesson 7: simple beats clever, every time

Clever code is hard to debug at 11pm when a store is down, hard to hand to the next developer, and hard to reason about when the bug report finally arrives six months later. We have rewritten enough of our own too-clever early code to treat readability as a feature. A straightforward approach a junior can follow is worth more than an elegant one that takes ten minutes to decode — because the cost of code is paid mostly in maintenance, not in writing it.

What we would do differently

Hindsight is unfairly clear. If we started the ten years over:

  • Adopt Symfony services and the modern controller patterns earlier — we hand-rolled admin pages in the AdminController era that became expensive to maintain once the platform moved on.
  • Invest in automated testing from year one, not year three. The cost of a missing test is paid by a customer, later, at the worst moment.
  • Standardise our admin-interface framework sooner. Too many early modules had bespoke back-office pages; a shared internal toolkit would have saved years of duplicate work.
  • Be more aggressive about removing little-used features. Every edge case kept alive is complexity carried forever — and complexity is where bugs and upgrade breakage hide.

What never changed

PrestaShop changed enormously across these ten years — Smarty to Twig, the Symfony migration, the 1.6 → 1.7 rebuild, the 8.x and 9.x lines. The principles did not:

PrincipleWhat it means in practice on PrestaShop
No overrides, everHooks, the module API and Symfony services only — nothing in /override.
Performance is non-negotiableEarly-exit hooks, scoped assets, cached repeat queries, a real ms budget.
Backward compatibility is a promiseVersion-detect and abstract the moving parts from line one — support 1.6 through 9.
Listen to customers over competitorsThe support inbox is the roadmap; direct developer support keeps that signal intact.
Simple beats cleverReadability is a feature; maintenance is where the cost lives.
Test on real storesProduction-shaped staging — real data volume, real module stack, real themes.

The throughline is ownership. None of these lessons make sense on a platform where you cannot see the code, override-or-not is not your decision, and "the next upgrade" is something a vendor does to you on their schedule. They are open-source lessons — which is exactly why we keep choosing to build here, a choice we examine in why owning your code matters more than ever and weigh against the rented-platform alternative in PrestaShop vs Shopify: a store you own or a store you rent. Ten years in, the modules we wrote in 2016 still run in 2026 — not because PrestaShop stood still, but because these six principles told us what to build so they would.

Tags: PrestaShop SEO
Share this post:
David Miller

David Miller

Over a decade of hands-on PrestaShop expertise. David builds high-performance e-commerce modules focused on SEO, checkout optimization, and store management. Passionate about clean code and measurable results.

Enjoyed this article?

Get our latest tips, guides and module updates delivered to your inbox.

Comments

No comments yet. Be the first!

Be the first to ask a question or share useful feedback.

Loading...
Back to top