DEV Community

Cover image for Debugging a Slow PrestaShop Store: Find the Bottleneck Before You Optimize
PrestaHero Team for PrestaHero

Posted on Edited on

Debugging a Slow PrestaShop Store: Find the Bottleneck Before You Optimize

When a PrestaShop store feels slow, the tempting response is to start enabling performance options: turn on caching, minify everything, compress images, install another optimization module, or upgrade the server.

That approach can improve performance, but it can also hide the actual problem.

A slow storefront is the result of work happening across several layers. Before the browser can display a product page, the request may pass through the web server, PHP, PrestaShop's dispatcher, database queries, modules and hooks, Smarty rendering, and finally the browser's CSS, JavaScript, images, fonts, and third-party scripts.

A delay at any of these layers can produce the same user complaint: "the site is slow."

The useful question is therefore not which optimization should I enable? It is where is the request spending its time?

Start by locating the delay
A practical investigation begins by separating three different symptoms.

If the browser spends a long time waiting before receiving the HTML document, investigate the backend. Hosting resources, PHP execution, database queries, modules, hooks, page generation, and caching are all possible causes.

If the HTML arrives reasonably quickly but important content appears late, the bottleneck has probably moved toward the rendering path. Large images, CSS, fonts, or other resources deserve attention.

If the page becomes visible quickly but remains sluggish or unresponsive, JavaScript execution and third-party scripts become stronger suspects.

These categories are not mutually exclusive. A store can have a slow backend and an oversized hero image at the same time. The purpose of this first classification is simply to stop treating every performance problem as the same problem.

Chrome DevTools gives you enough information to begin this investigation. Open the Network panel, reload a representative page, select the main document request, and inspect its Timing information.

Pay particular attention to the waiting time for the server response, commonly represented by Time to First Byte (TTFB).

TTFB is useful, but it is not a diagnosis. A high value tells you that substantial time passed before the response began arriving. It does not tell you whether that time was consumed by an overloaded server, PHP, MySQL, a slow module, an external API call, or the complete PrestaShop page-generation pipeline.

That distinction matters.

Compare page types before blaming the server

Testing only the homepage can send an investigation in the wrong direction.

Instead, test several representative controllers: the homepage, a product page, a category page, and a relatively simple CMS page. Keep the test conditions as consistent as possible.

Suppose all of them have slow server response times. Infrastructure, global modules, shared database work, or other application-wide processing become plausible suspects.

Now suppose the CMS page responds quickly while product and category pages are consistently slow. The hosting environment can clearly produce a fast response under some conditions, so immediately upgrading the server becomes harder to justify.

The difference may instead come from page-specific work: product queries, pricing logic, navigation modules, faceted search, recommendation modules, or hooks executed only on catalog controllers.

This comparison is one of the simplest ways to reduce the search space before touching production configuration.

Determine whether you are repeatedly generating the same HTML

PrestaShop is a dynamic application. Serving a product page can require PHP execution, SQL queries, module and hook execution, Smarty processing, and HTML generation.

Without effective full-page caching, eligible requests may repeatedly perform much of that work.

That gives you a useful experiment: compare an uncached request with subsequent requests to the same eligible page.

If the first request is expensive but later cache hits become dramatically faster, repeated application processing is an important part of the latency. If repeated requests remain slow, either the cache is missing, the page is intentionally not cacheable, cache variants are preventing reuse, or the bottleneck exists somewhere that the page cache does not eliminate.

Do not verify caching by checking whether a configuration switch says "Enabled." Verify the behavior.

Depending on the implementation, useful evidence includes cache-hit statistics, generated cache files, cached URL records, logs, response headers, or a measurable difference between misses and hits.

For example, one PrestaShop implementation I examined, PrestaHero's Super Speed module, intercepts eligible requests from a Dispatcher override. On a valid cache hit, cached HTML can be returned before normal dispatch continues. On a miss, PrestaShop completes the normal rendering path and the generated HTML can subsequently be stored.

That architecture illustrates why a real full-page cache can reduce backend work: a hit is not merely caching one database query or one Smarty fragment. It can bypass much of the normal request-generation path.

But ecommerce caching immediately creates another problem.

A cache key is part of your correctness model

Imagine caching: https://shop.example.com/product/42

and serving exactly the same HTML to every request for that URL.
That might be incorrect.

Two visitors requesting the same URL may have different currencies, countries, customer groups, cart states, languages, or prices. Modules may also render personalized blocks.

A useful ecommerce cache therefore needs to answer two questions:

  1. Which requests can safely reuse generated HTML?
  2. Which dimensions require separate cache variants or dynamic rendering?

In the Super Speed implementation, for example, the page-cache key accounts for request context including currency, customer groups, country, cart presence, and user-agent grouping, while cache records are also language- and shop-aware.

Dynamic regions can be handled separately. Selected hooks can be rendered as placeholders in cached HTML and refreshed through AJAX after the cached shell loads. Cart/customer information and prices also have optional dynamic-loading mechanisms.

The general principle applies regardless of which cache implementation you use: maximizing cache hits is not the only objective. You need to maximize correct cache hits.

Adding more dimensions to the key improves isolation but increases cache cardinality. Moving content to AJAX preserves freshness but introduces additional requests. Short cache lifetimes improve freshness but reduce reuse.

Caching an ecommerce application is therefore a correctness/performance tradeoff, not simply an on/off optimization.

Profile hooks when only some pages are slow
If caching does not explain the problem, modules and hooks are a logical next layer.

PrestaShop's hook architecture makes the platform extensible, but it also means a request may execute code from many independent modules before the response is complete.

Consider a module attached to a product-page hook that performs an expensive SQL query or calls an external service. If that hook takes 800 ms, every request executing it inherits approximately that cost even if the rest of the application is healthy.

This is why page-type comparison is so useful. A fast CMS controller and slow product controller suggest that you should investigate what additional work occurs on the product request.

Profiling is better than guessing.

Measure hook execution where possible and identify unusually expensive modules. Super Speed's System Analytics, for example, can record hook execution time and expose slow hooks for investigation. Similar instrumentation can also be implemented with your own profiling tools.

Once you find a suspicious module, temporarily disabling it can be a useful controlled experiment. If response time changes substantially under comparable conditions, you have much stronger evidence than you would get from randomly changing global performance settings.

Finding the slow module is not the same as fixing it, however. The underlying issue might be an inefficient query, unnecessary processing, an external API dependency, or functionality executing on pages where it is not needed.

The profiler tells you where to look. It does not replace debugging.

Separate transfer size from JavaScript execution
Once server response is acceptable, move to the browser.

One common mistake is treating every JavaScript problem as a file-size problem.

Minification removes unnecessary characters and can reduce transfer size.
It cannot make an expensive algorithm cheap, prevent a third-party service from performing heavy work, or stop a module from attaching unnecessary client-side behavior.

In DevTools, inspect both the Network and Performance views.

For CSS and JavaScript resources, ask:

  • Is this resource unusually large?
  • Is it required on this page?
  • Is it render-blocking?
  • Does a third-party origin account for significant work?
  • Does JavaScript keep the main thread busy after the page becomes visible?
  • Are multiple modules shipping overlapping libraries or functionality?
  • If transfer size is the issue, minification and compression may help. If execution is the issue, investigate the code itself.

A smaller slow script can still be a slow script.

Treat images according to their role on the page
Images deserve similar diagnostic discipline.

Sorting the Network panel by image size is useful, but "large file" does not automatically mean "bad image." A full-width product photograph naturally requires more data than a small thumbnail.

Look instead for mismatches between what is downloaded and what is actually needed.

A 2000-pixel image displayed as a 300-pixel thumbnail is suspicious. So is an unnecessarily heavy format or dozens of below-the-fold images loaded during the initial request.

For suitable images, resize them to appropriate dimensions, compress them, and use efficient formats such as WebP where your delivery pipeline supports them. Lazy loading can reduce initial work for off-screen images.

Be careful with the opposite extreme. The main above-the-fold image may be your Largest Contentful Paint element. Delaying that resource can make performance worse rather than better.

Optimization should follow the role of the resource, not a blanket rule that every image should be lazy-loaded.

Do not confuse the different kinds of cache
"Enable cache" is ambiguous because several caching mechanisms solve different problems.

A full-page cache avoids regenerating an eligible HTML response.

Smarty caching reduces repeated template-processing work when PrestaShop does need to generate a page.

Browser caching lets a visitor reuse static resources such as CSS, JavaScript, fonts, and images instead of downloading identical assets repeatedly.

These mechanisms operate at different layers.

If your TTFB is dominated by expensive page generation, increasing the browser-cache lifetime of your CSS will not solve that backend bottleneck. If HTML arrives quickly but the browser repeatedly downloads unchanged assets, full-page caching does not address the actual problem either.

Compression is different again. GZIP reduces the number of bytes transferred for supported text resources, but it does not eliminate PHP execution or JavaScript runtime work.

Treat each mechanism according to the cost it removes.

A large database is not automatically a slow database
Database size is another area where correlation is often mistaken for diagnosis.

A long-running PrestaShop installation can accumulate connection logs, page-view statistics, abandoned carts, guest records, expired pricing data, and other operational records. Cleaning unnecessary data can reduce storage and improve some operations.

But database size alone is weak evidence of a performance bottleneck.
A large, properly indexed table queried efficiently can perform well. A much smaller table queried badly hundreds of times during a request can perform terribly.

If you suspect MySQL, investigate table sizes, slow queries, query frequency, indexes, and the modules issuing those queries.

Housekeeping and query optimization are different tasks.

If you remove historical or statistical records, back them up when appropriate and understand what is being deleted. A cleanup tool cannot compensate for an inefficient query plan.

Change one meaningful variable at a time

After investigation, you may discover several bottlenecks:

Server response OK
Full-page cache MISS / misconfigured
Product hook 740 ms
Third-party JS expensive
Product hero image oversized
Browser cache OK
Database no obvious issue

This is far more actionable than a PageSpeed score by itself.
Now you can make controlled changes.

Fix or isolate the slow hook and repeat the same product-page test. Correct the cache configuration and verify actual hits. Optimize the hero image and measure the rendering result again.

Avoid changing ten performance settings simultaneously. If TTFB drops from 1.4 seconds to 350 ms after ten unrelated changes, you know the store improved but you learned very little about why.

Performance debugging is most useful when every meaningful change produces evidence.

Build a bottleneck map, not a collection of optimization switches
A slow PrestaShop store is not a single technical condition.

The delay can occur before HTML generation, during application processing, inside a module or database query, while transferring assets, during rendering, or while JavaScript occupies the browser's main thread.
The most reliable workflow is therefore:

Observe the symptom
↓
Locate the layer
↓
Measure the suspected bottleneck
↓
Change one relevant variable
↓
Repeat the same test
↓
Verify the improvement

Caching, minification, compression, image optimization, database cleanup, and faster infrastructure are all useful tools. None of them should be the starting assumption.

Start with the request.

Find where the time goes.

Then optimize the layer that is actually responsible.

Top comments (0)