<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Peter Y</title>
    <description>The latest articles on DEV Community by Peter Y (@flashpeter7).</description>
    <link>https://dev.to/flashpeter7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3920688%2F9531832a-10c8-45e8-a7d6-1829d58f5c42.png</url>
      <title>DEV Community: Peter Y</title>
      <link>https://dev.to/flashpeter7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/flashpeter7"/>
    <language>en</language>
    <item>
      <title>PrestaShop Behind a Load Balancer: What Breaks and How to Fix It</title>
      <dc:creator>Peter Y</dc:creator>
      <pubDate>Fri, 08 May 2026 20:23:27 +0000</pubDate>
      <link>https://dev.to/flashpeter7/prestashop-behind-a-load-balancer-what-breaks-and-how-to-fix-it-50cp</link>
      <guid>https://dev.to/flashpeter7/prestashop-behind-a-load-balancer-what-breaks-and-how-to-fix-it-50cp</guid>
      <description>&lt;h1&gt;
  
  
  PrestaShop Behind a Load Balancer: What Breaks and How to Fix It
&lt;/h1&gt;

&lt;p&gt;PrestaShop on a single server is fine. PrestaShop behind a load balancer with auto-scaling nodes — that's where the fun begins. The framework was never built for this, and it shows.&lt;/p&gt;

&lt;p&gt;I've been running a B2B store on PrestaShop for several years now. ~300k SKUs, hundreds of orders a day, auto-scaling on GCP. Here's what went wrong and how we dealt with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  800 Queries Per Product Page. Yes, Really.
&lt;/h2&gt;

&lt;p&gt;A single product page in PrestaShop fires about 800 SQL queries. A category listing — around 2,000. Not a bug. That's just PrestaShop being PrestaShop.&lt;/p&gt;

&lt;p&gt;On one server you stick Redis in front of it and forget about it. On multiple nodes — not so simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Desync Between Nodes
&lt;/h2&gt;

&lt;p&gt;PrestaShop caches query results locally. Redis, Memcached, whatever — it's per-node. So each node builds its own cache.&lt;/p&gt;

&lt;p&gt;What happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node A caches a product at 10:00&lt;/li&gt;
&lt;li&gt;Node B caches it at 10:02&lt;/li&gt;
&lt;li&gt;Admin updates the price at 10:05&lt;/li&gt;
&lt;li&gt;Both nodes keep serving stale data with different prices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obvious idea: shared Redis. Problem: network latency on every hit. At 800 queries per page, even 1ms extra per query gives you almost a second of overhead. Your "fast cache" is now slower than just hitting the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  How We Actually Solved It
&lt;/h2&gt;

&lt;p&gt;We didn't fight the architecture. We went around it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sticky sessions via Cloudflare.&lt;/strong&gt; Visitor lands on a node, stays on that node for the session. No desync from the user's point of view.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local Redis on each node, TTL 10 minutes.&lt;/strong&gt; Fast, simple, no network hop. We talked to management: "product descriptions might be 10 minutes behind." They said fine. For a B2B catalog that doesn't change every minute, this is a non-issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table blacklist.&lt;/strong&gt; This is the part that actually matters. We built a list of tables that must never be cached — any SQL query touching these tables goes straight to the database.&lt;/p&gt;

&lt;p&gt;The blacklist breaks down like this:&lt;/p&gt;

&lt;p&gt;Carts and sessions — &lt;code&gt;cart&lt;/code&gt;, &lt;code&gt;cart_product&lt;/code&gt;, &lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;guest&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;. Changes on every click.&lt;/p&gt;

&lt;p&gt;Orders and payments — &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_detail&lt;/code&gt;, &lt;code&gt;order_history&lt;/code&gt;, payment gateway tables. You don't want stale financial data. Ever.&lt;/p&gt;

&lt;p&gt;Stock — &lt;code&gt;stock_available&lt;/code&gt;. Showing wrong availability is worse than a slow page.&lt;/p&gt;

&lt;p&gt;Analytics — &lt;code&gt;connections&lt;/code&gt;, &lt;code&gt;page_viewed&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;. Write-heavy, would trash the cache constantly anyway.&lt;/p&gt;

&lt;p&gt;Third-party modules — anything that deals with orders, wishlists, promotions, discounts. Every time you install a new module, you check its tables and add them to the blacklist if needed. This never ends.&lt;/p&gt;

&lt;p&gt;Configuration — &lt;code&gt;configuration&lt;/code&gt;, &lt;code&gt;configuration_lang&lt;/code&gt;. Admin changes a setting — it needs to work immediately.&lt;/p&gt;

&lt;p&gt;The rule is dead simple: if the table changes more often than once per 10 minutes, it goes on the blacklist.&lt;/p&gt;

&lt;h3&gt;
  
  
  What It Gave Us
&lt;/h3&gt;

&lt;p&gt;Second hit on a warm cache:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product page: 800 → 200–300 queries (about 65% less)&lt;/li&gt;
&lt;li&gt;Category listing: 2,000 → 600 queries (about 70% less)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No distributed cache. No invalidation logic. No latency overhead. Just sticky sessions, local Redis, and a blacklist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying Code When There's No Single Server
&lt;/h2&gt;

&lt;p&gt;On one box it's &lt;code&gt;git pull &amp;amp;&amp;amp; clear cache&lt;/code&gt;. With N nodes the questions pile up. How does code get everywhere? What about shared files? What about PrestaShop's class cache?&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared Files on NFS
&lt;/h3&gt;

&lt;p&gt;Some stuff has to be shared — images, documents, uploads. An admin goes into backoffice, uploads a banner — that image lands on one node. Others don't see it. So we mount certain directories from NFS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product images and module media (banners, sliders, brand logos)&lt;/li&gt;
&lt;li&gt;Documents, downloads, invoices&lt;/li&gt;
&lt;li&gt;Upload directory&lt;/li&gt;
&lt;li&gt;Logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else — PHP, vendor, compiled assets — lives on each node's local disk. You do not want to serve PHP from NFS. Trust me.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Deploy Machine
&lt;/h3&gt;

&lt;p&gt;We have a dedicated deploy box. It shares the NFS mount with web nodes. Deploy looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SSH into deploy machine&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git pull&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run build&lt;/code&gt; (compiles Bootstrap and friends)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rsync&lt;/code&gt; to all web nodes, excluding NFS directories&lt;/li&gt;
&lt;li&gt;Cache dirs get wiped during rsync — nodes rebuild class maps on next request&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The NFS directories are symlinked on each node — &lt;code&gt;/img&lt;/code&gt; points to NFS, everything else is local. Rsync skips the symlinked paths.&lt;/p&gt;

&lt;p&gt;What this gives you: code hits all nodes within seconds, PHP serves from local disk (fast), shared files are always in sync, and cache resets automatically. Good enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modules: The Worst Part
&lt;/h2&gt;

&lt;p&gt;This is where PrestaShop really punishes you for having infrastructure.&lt;/p&gt;

&lt;p&gt;When you click "Install" on a module, it can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drop files into &lt;code&gt;/override/&lt;/code&gt;, overriding core classes&lt;/li&gt;
&lt;li&gt;Run arbitrary SQL — create tables, alter schema, insert rows&lt;/li&gt;
&lt;li&gt;Copy assets all over the filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No migrations. No rollback. It's a side-effect machine.&lt;/p&gt;

&lt;p&gt;On multiple nodes this is a nightmare. You can't just commit a module and deploy — it needs its install hooks. You can't install via admin panel on prod — it only runs on one node.&lt;/p&gt;

&lt;h3&gt;
  
  
  Module Surgery
&lt;/h3&gt;

&lt;p&gt;Every marketplace module goes through prep before it gets anywhere near production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strip the overrides.&lt;/strong&gt; Modules come with an &lt;code&gt;/override/&lt;/code&gt; folder. We empty it. A developer manually reviews what the module wanted to override and merges it into the project's own &lt;code&gt;/override/&lt;/code&gt; directory by hand. Resolves conflicts, makes it a normal commit. Reviewable, reversible.&lt;/p&gt;

&lt;p&gt;Why? Because if two modules try to override the same core method, you get a silent race condition. On a single server you might not notice. On multiple nodes with different cache states — good luck debugging that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review the install() method.&lt;/strong&gt; Read what SQL it runs. Know what it'll do to your database before it does it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy the code first.&lt;/strong&gt; Commit the cleaned module, &lt;code&gt;git pull&lt;/code&gt; on deploy machine, rsync to all nodes. At this point every node has the module files but the module isn't installed yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then hit Install in the admin panel.&lt;/strong&gt; Since we stripped the overrides, the installer only does its database work — creates tables, registers hooks. Doesn't matter which node handles the request, the DB is shared and the code is already everywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rsync once more.&lt;/strong&gt; PrestaShop rebuilds its class index after install. One more rsync pushes that to all nodes.&lt;/p&gt;

&lt;p&gt;Tedious? Yes. But it works every time. And on production I'll take boring and reliable over clever and fragile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not Just Ditch PrestaShop?
&lt;/h2&gt;

&lt;p&gt;Fair question after all of the above.&lt;/p&gt;

&lt;p&gt;Because a €100 module from the marketplace replaces months of custom development. Mollie integration is free. Need gift cards? Wishlists? Complex discount rules? Someone already built it, battle-tested it on real stores, and sells it for the price of a dinner.&lt;/p&gt;

&lt;p&gt;Try getting that on a custom headless build. You'll burn through your budget before you ship anything.&lt;/p&gt;

&lt;p&gt;PrestaShop's value was never its architecture — the architecture is showing its age. The value is the ecosystem. For a small or mid-size business, solving commerce problems with off-the-shelf modules at these prices is hard to beat.&lt;/p&gt;

&lt;p&gt;Yes, you pay for it with operational complexity when you scale. Everything in this article is that tax. But you're handling it with a small team and a sane budget, while companies on "enterprise" platforms throw 10x the money at consultants and ship slower.&lt;/p&gt;

&lt;p&gt;That's the trade-off. If your team can handle the rough edges — and now you have a playbook — PrestaShop still makes a lot of sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;PrestaShop on multiple nodes breaks in three places: cache, deployment, and modules.&lt;/li&gt;
&lt;li&gt;Cache: sticky sessions + local Redis + table blacklist. 800 queries → 300. No distributed cache needed.&lt;/li&gt;
&lt;li&gt;Deploy: dedicated deploy machine, rsync to nodes, NFS for shared files only. PHP always on local disk.&lt;/li&gt;
&lt;li&gt;Modules: strip overrides, review SQL, deploy code first, install via admin second. Every time. No shortcuts.&lt;/li&gt;
&lt;li&gt;PrestaShop's ecosystem is worth the operational pain — if you know how to manage it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Struggling with a similar setup? Tell me.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: prestashop, ecommerce, devops, scaling&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>devops</category>
      <category>performance</category>
      <category>php</category>
    </item>
  </channel>
</rss>
