Knowledge Base Guide

PrestaShop Performance Optimization: Speed Up Your Store

Complete performance tuning guide — OPcache, MySQL tuning, CCC configuration, image optimization, caching strategies, and Core Web Vitals.

Why Store Speed Is Not Optional

Every 100 milliseconds of additional load time costs you conversions. Amazon found that a 100ms delay reduced revenue by 1%. Google confirmed that pages loading in more than 3 seconds lose 53% of mobile visitors before they see your products.

For a PrestaShop store, speed affects three things directly:

  • Conversion rates: A store that loads in 2 seconds converts at roughly double the rate of one that loads in 5 seconds. Your customers will not wait — they will buy from someone faster.
  • SEO rankings: Google uses page speed as a ranking factor. Since 2021, Core Web Vitals are part of the algorithm. A slow store ranks lower, gets less organic traffic, and pays more for visibility.
  • Mobile experience: Over 70% of e-commerce traffic is mobile. Slower processors, less memory, worse connections. If your store is slow on desktop, it is painful on mobile.
Speed optimization is not a one-time task — it is an ongoing discipline. Every module you install, every theme change, every product image affects performance. Treat speed as a feature you maintain, not a project you complete.

Measure Before You Optimize

The worst thing you can do is start "optimizing" without knowing where your actual problems are. Always measure first.

The Right Tools

  • Google PageSpeed Insights: Free, uses real Chrome user data (CrUX). Test your homepage, a category page, and a product page — these are your most common entry points.
  • GTmetrix: Gives you a waterfall chart showing exactly what loads, in what order, and how long each request takes. Invaluable for finding bottlenecks.
  • WebPageTest: The most detailed tool available. Test from different locations and connection speeds with filmstrip views.

Core Web Vitals Explained

These are the three metrics Google uses to evaluate user experience:

  • LCP (Largest Contentful Paint): Time until the largest visible element finishes loading. Target: under 2.5 seconds. Most PrestaShop stores struggle here — unoptimized images and render-blocking scripts are the culprits.
  • INP (Interaction to Next Paint): How long the page takes to respond to clicks and taps. Replaced FID in March 2024. Target: under 200ms. Heavy JavaScript and poorly written module scripts cause high INP.
  • CLS (Cumulative Layout Shift): How much the layout jumps during loading. Target: under 0.1. Images without dimensions, late-loading banners, and font swaps cause CLS.

Realistic Targets

A feature-rich PrestaShop store will never score 100 on PageSpeed. Aim for: mobile 50-70, desktop 80-95, LCP under 3s mobile / 2s desktop, total page weight under 2MB, under 80 HTTP requests.

Do not chase a perfect PageSpeed score. A score of 65 with 3% conversion rate beats a score of 98 on a stripped-down page nobody buys from. Optimize for real user experience, not a number.

Server Optimization

No frontend tricks can fix a slow server. If your server takes 2 seconds to generate HTML before the browser even starts loading assets, you have already lost.

PHP OPcache Configuration

OPcache stores precompiled PHP bytecode in memory so PHP does not re-parse files on every request. For PrestaShop (hundreds of PHP files per page), this is mandatory.

opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.save_comments=1

The defaults are too low for PrestaShop. max_accelerated_files must be at least 20000 (default is 4000, but a typical PS install has 10,000-15,000 PHP files). Set memory_consumption to 128-256MB — if OPcache memory fills up, it evicts entries and you lose the benefit.

On cPanel hosts with validate_timestamps=0, OPcache will NEVER re-read files from disk. You must reset it via a web request after every deployment — CLI resets only clear the CLI cache, not the web cache.

MySQL / MariaDB Tuning

A typical PrestaShop product page runs 50-200 SQL queries. The single most important database setting is:

[mysqld]
# Set to 50-70% of available RAM on dedicated DB server
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2

# MySQL 5.7 / MariaDB only (removed in MySQL 8.0)
query_cache_type = 1
query_cache_size = 64M

# Find problem queries
slow_query_log = 1
long_query_time = 1

# Connection settings
max_connections = 150
tmp_table_size = 64M
max_heap_table_size = 64M

The innodb_buffer_pool_size determines how much database data is held in RAM. If your database is 500MB and the buffer pool is 1GB, most queries are served from memory. Enable the slow query log and review it weekly — queries taking over 1 second are problems waiting to happen during peak traffic.

Hosting: Shared vs VPS vs Dedicated

  • Shared hosting ($5-15/month): You share CPU and RAM with hundreds of sites. Acceptable only for very small stores under 500 products.
  • VPS ($20-60/month): Dedicated resources. The sweet spot for most stores. Get at least 4GB RAM, 2 CPU cores, SSD storage.
  • Dedicated ($80-300/month): For high-traffic stores (1000+ daily orders) or catalogs over 100,000 products.
If you are on shared hosting and your store is slow, switching to a VPS will give you a bigger speed improvement than all other optimizations combined.

PHP-FPM and Redis

Use PHP-FPM instead of mod_php — it runs PHP as a separate service, reducing memory usage and improving process management. Use Redis for session and cache storage instead of the filesystem. Configure in app/config/parameters.php:

'ps_cache_enable' => true,
'ps_caching' => 'CacheRedis',

PrestaShop Built-in Optimizations

CCC (Combine, Compress, Cache)

Found in Advanced Parameters → Performance, CCC combines CSS/JS files into single files and minifies them. Always enable on production. Watch for pitfalls:

  • Files with defer or async attributes stay separate (by design)
  • External files (Google Fonts, Stripe.js) are never combined
  • Poorly coded modules can break when CCC reorders assets — if enabling CCC breaks your checkout, disable it and identify the problematic module
  • Always clear cache and test thoroughly after enabling

Smarty Template Settings

Set template compilation to "Recompile templates if the files have been updated" on production. Never use "Force compilation" — it recompiles every template on every page load.

Debug Mode — Check This First

Debug mode disables all caching, forces template recompilation, and logs everything. Verify it is off:

// In app/config/defines.inc.php — MUST be false on production
define('_PS_MODE_DEV_', false);

We have seen stores running debug mode for months. Their "slow store" problem vanished when this single setting was corrected.

Disable Unnecessary Modules

Every enabled module hooks into PrestaShop's event system. A fresh install comes with 80+ modules. Each one loads PHP classes, may register CSS/JS on every page, executes hook callbacks, and may run database queries — even when returning empty content.

Go through Modules → Module Manager and uninstall anything you do not actively use. If you have three analytics modules doing the same thing, keep one.

Image Optimization

Images are typically 60-80% of a page's total weight. This is where most stores have the biggest room for improvement.

WebP and Proper Dimensions

WebP images are 25-35% smaller than JPEG with no visible quality loss. PrestaShop 8.x supports WebP natively. For older versions, use server-side conversion or a module.

The most common waste: serving 2000x2000px images in 300px thumbnails. Configure image types in Design → Image Settings to match your theme's actual display sizes. Do not upload 4000px source images "just in case" — 1200px is enough for product page zoom on retina displays.

Lazy Loading

Defer loading of below-the-fold images until the user scrolls to them:

<img src="product.jpg" loading="lazy" width="300" height="300" alt="Product Name">

Do NOT lazy-load above-the-fold images (logo, hero banner, first product row) — those affect LCP and must load immediately.

Image Regeneration

After changing image dimensions, regenerate existing images via Design → Image Settings or CLI:

php bin/console prestashop:image:regenerate --type=products

Frontend Optimization

Minimize HTTP Requests

Check your waterfall chart in GTmetrix. Over 100 requests means trouble. Common culprits: modules loading their own CSS/JS files, Google Fonts with multiple weights, social media widgets, and multiple analytics tools.

Critical CSS

Browsers stop rendering until all CSS in the <head> is downloaded. Critical CSS extracts only the styles needed for the initial viewport and inlines them. The full stylesheet loads asynchronously. This can reduce perceived load time by 1-3 seconds on mobile, but requires regeneration whenever theme CSS changes.

JavaScript: Defer and Async

Use defer for most module scripts (downloads in parallel, executes after HTML parsing). Use async only for independent scripts like analytics. In PrestaShop 1.7+:

$this->context->controller->registerJavascript(
    'module-my-script',
    'modules/mymodule/views/js/front.js',
    ['position' => 'bottom', 'priority' => 200, 'attribute' => 'defer']
);

Font Optimization

Custom fonts silently add 200-400KB of downloads. Best practices:

  • Self-host fonts instead of Google Fonts (eliminates extra DNS lookup)
  • Subset to only the characters you need (Latin-only subsets are 60-80% smaller)
  • Use font-display: swap so text is visible immediately in a fallback font
  • Limit to 2 weights — regular (400) and bold (700) cover most needs
  • Use WOFF2 format — best compression, universal browser support
@font-face {
    font-family: 'YourFont';
    src: url('/themes/your-theme/assets/fonts/yourfont.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

CDN Basics

A CDN serves static files from servers close to your visitors. Cloudflare is the most popular free option. Configure a CDN domain in Advanced Parameters → Performance → Media Servers for images, CSS, and JS.

Database Optimization

PrestaShop databases grow silently. Tables that were fine at launch become problems after two years of accumulated data.

Clean Up Old Carts

ps_cart and ps_cart_product grow with every visitor — including bots and abandoned sessions. After a year, these tables can have millions of rows.

-- Delete cart products for old abandoned carts (not linked to orders)
DELETE cp FROM ps_cart_product cp
INNER JOIN ps_cart c ON cp.id_cart = c.id_cart
LEFT JOIN ps_orders o ON c.id_cart = o.id_cart
WHERE o.id_order IS NULL
AND c.date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH);

-- Delete the empty carts
DELETE c FROM ps_cart c
LEFT JOIN ps_orders o ON c.id_cart = o.id_cart
LEFT JOIN ps_cart_product cp ON c.id_cart = cp.id_cart
WHERE o.id_order IS NULL AND cp.id_cart IS NULL
AND c.date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH);
Always back up your database before running DELETE queries. Always test on staging first. The LEFT JOIN + IS NULL pattern ensures carts linked to orders are never deleted.

Clean Up Logs and Connections

-- Application logs
DELETE FROM ps_log WHERE date_add < DATE_SUB(NOW(), INTERVAL 30 DAY);

-- Visitor tracking
DELETE FROM ps_connections_page WHERE id_connections IN (
    SELECT id_connections FROM ps_connections
    WHERE date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH)
);
DELETE FROM ps_connections WHERE date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH);

-- Orphaned guest records
DELETE g FROM ps_guest g
LEFT JOIN ps_connections c ON g.id_guest = c.id_guest
WHERE c.id_guest IS NULL;

-- Search stats, 404 logs, email logs
DELETE FROM ps_statssearch WHERE date_add < DATE_SUB(NOW(), INTERVAL 6 MONTH);
DELETE FROM ps_pagenotfound WHERE date_add < DATE_SUB(NOW(), INTERVAL 30 DAY);
DELETE FROM ps_mail WHERE date_add < DATE_SUB(NOW(), INTERVAL 3 MONTH);

Clean Up Search Index

If you use an external search solution (Elasticsearch, Algolia), these tables are dead weight:

TRUNCATE TABLE ps_search_index;
TRUNCATE TABLE ps_search_word;

Optimize Tables and Indexes

After large deletions, reclaim disk space:

OPTIMIZE TABLE ps_cart, ps_cart_product, ps_connections,
    ps_connections_page, ps_guest, ps_log;

Add missing indexes for common queries:

-- Check existing indexes first: SHOW INDEX FROM ps_cart;
ALTER TABLE ps_cart ADD INDEX idx_cart_date (date_add);
ALTER TABLE ps_connections ADD INDEX idx_conn_date (date_add);
ALTER TABLE ps_orders ADD INDEX idx_orders_ref (reference);
ALTER TABLE ps_product ADD INDEX idx_product_ref (reference);

Use EXPLAIN on slow queries to verify indexes are being used — if the "type" column shows "ALL", it means a full table scan.

Caching Strategies

Full Page Cache

The most dramatic improvement available. Without it, every request runs hundreds of PHP files and 100+ queries (200-500ms). With full page cache, the same page serves in 5-20ms.

Varnish is the industry standard. nginx FastCGI cache is simpler if you already use nginx:

fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=PS:100m inactive=60m;

set $skip_cache 0;
if ($http_cookie ~* "PrestaShop-") { set $skip_cache 1; }
if ($request_uri ~* "/cart|/order|/my-account|/admin") { set $skip_cache 1; }

location ~ \.php$ {
    fastcgi_cache PS;
    fastcgi_cache_valid 200 10m;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
}

The challenge is cache invalidation — clearing cached pages when products, prices, or stock change. This complexity is why many stores skip full page caching.

Object Caching and Browser Caching

Object caching (via Redis) stores expensive query results in memory. Less dramatic than full page cache (30-50% query time reduction) but much simpler — PrestaShop handles invalidation automatically.

Browser caching headers tell visitors' browsers to store static files locally:

# Apache (.htaccess)
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType font/woff2 "access plus 1 year"
</IfModule>

Common Performance Killers

  • Too many modules (50+): Each adds autoloader overhead, hook callbacks, CSS/JS, and queries. A store with 30 modules always outperforms one with 80. There is no such thing as a zero-cost module.
  • Modules loading assets everywhere: A popup module that only fires on the homepage but loads 150KB of JavaScript on every page is pure waste. Check your waterfall for irrelevant module assets.
  • Heavy homepage sliders: 3-5 high-res images plus a JS library = 1-5MB for a component fewer than 1% of users interact with past the first slide. Use a single static hero image instead.
  • Unoptimized custom themes: Full Bootstrap loaded for 3 components, unminified CSS/JS, no image dimensions, synchronous scripts. Require performance audits from theme developers.
  • Missing database indexes: A query with a proper index takes 10ms. Without one, it takes 5 seconds — and you will not notice until traffic peaks.

Performance Monitoring Checklist

Quick Checks (5 minutes)

  • Run PageSpeed Insights on homepage, category page, product page
  • Verify _PS_MODE_DEV_ is false
  • Confirm Smarty is NOT set to "Force compilation"
  • Check that CCC is enabled
  • Verify OPcache is active via phpinfo()

Monthly Maintenance (30 minutes)

  • Clean up abandoned carts in ps_cart / ps_cart_product (older than 3 months)
  • Clean up ps_log, ps_connections, ps_connections_page, ps_guest
  • Run OPTIMIZE TABLE on cleaned tables
  • Review the slow query log
  • Uninstall any unused modules

Quarterly Review (2 hours)

  • Full GTmetrix test from multiple locations — compare with previous quarter
  • Review Core Web Vitals in Google Search Console
  • Audit module assets for unnecessary CSS/JS
  • Check image sizes — ensure no oversized uploads
  • Review server resource usage (CPU, RAM, disk I/O)
  • Test on a real mobile device, not just emulation
  • Verify browser caching headers
  • Check PHP error logs (errors consume resources)

After Every Deployment

  • Clear PrestaShop cache
  • Reset OPcache if validate_timestamps=0
  • Run a quick PageSpeed test for regressions
  • Check browser console for JavaScript errors
  • Test the checkout flow end-to-end

Start Here

Performance optimization is a process, not a destination. Start with the four highest-impact items: fix your server configuration, optimize your images, disable unnecessary modules, and clean your database. These alone resolve 80% of performance issues on most PrestaShop stores.

Measure before and after every change. Keep a log. The best optimization is the one your customers notice — faster image loading and a responsive checkout translate directly into trust, satisfaction, and conversions.

More guides available

Browse our knowledge base for more practical PrestaShop tutorials, or reach out if you need help.

Loading...
Back to top