DEV Community

Magevanta
Magevanta

Posted on • Originally published at magevanta.com

PHP OPcache Tuning for Magento 2: A Complete Guide

PHP OPcache is one of the highest-impact, lowest-effort performance wins available to any Magento 2 store. A misconfigured — or missing — OPcache can single-handedly cause slow page loads, high CPU usage, and poor Time to First Byte (TTFB) even when everything else is set up correctly. This guide covers everything you need to know to tune OPcache specifically for Magento 2.

What Is OPcache and Why Does It Matter for Magento?

Every time PHP executes a .php file, it goes through two steps:

  1. Compile the source code into opcodes (machine-readable bytecode)
  2. Execute those opcodes

Without OPcache, step 1 happens on every single request. Magento 2 loads hundreds of PHP files per request — framework classes, modules, generated code, interceptors, plugins — so repeated compilation is enormously wasteful.

OPcache stores the compiled bytecode in shared memory. On subsequent requests, PHP skips compilation entirely and jumps straight to execution. The result: significantly lower CPU usage and faster response times.

In production environments, a well-tuned OPcache can reduce PHP execution time by 30–70% compared to no cache at all.

Checking Your Current OPcache Status

Before tuning, check what you're working with:

php -r "print_r(opcache_get_status());" 2>/dev/null | head -40
Enter fullscreen mode Exit fullscreen mode

Or create a quick info page (temporarily, never leave this in production):

<?php opcache_reset(); echo json_encode(opcache_get_status(), JSON_PRETTY_PRINT);
Enter fullscreen mode Exit fullscreen mode

You can also use the opcache-gui project for a visual dashboard.

Key metrics to watch:

  • memory_usage.used_memory vs memory_consumption — are you running out?
  • opcache_statistics.misses — high misses = cache too small or files not being cached
  • opcache_statistics.oom_restarts — out-of-memory restarts are a red flag

Recommended OPcache Settings for Magento 2

Add or update the following in your php.ini or a dedicated /etc/php/8.x/fpm/conf.d/10-opcache.ini:

; Enable OPcache
opcache.enable=1
opcache.enable_cli=1

; Memory: 512MB is a good starting point for Magento
opcache.memory_consumption=512

; Number of interned strings (shared string pool)
opcache.interned_strings_buffer=64

; Max number of files to cache
; Magento 2 can easily have 20,000+ files — give headroom
opcache.max_accelerated_files=65407

; Revalidation frequency (seconds)
; In production, set to 0 and rely on deploy-time cache clear
opcache.revalidate_freq=0

; Validate timestamps: set to 0 in production (disable file change checks)
opcache.validate_timestamps=0

; Optimization level (max)
opcache.optimization_level=0x7FFEBFFF

; Save comments (required for Magento's annotation parsing)
opcache.save_comments=1

; File cache path (optional disk-based fallback)
; opcache.file_cache=/var/www/.opcache

; JIT (PHP 8+) — optional, see below
opcache.jit=1255
opcache.jit_buffer_size=128M
Enter fullscreen mode Exit fullscreen mode

Let's break down the critical ones.

opcache.memory_consumption

The default of 128MB is almost always too small for Magento 2. With hundreds of modules, generated interceptors, and compiled DI classes, you can easily exceed 200MB. Set this to at least 256MB, preferably 512MB on production.

If oom_restarts is > 0 in your status output, increase this value immediately.

opcache.max_accelerated_files

This controls how many files OPcache can store. The value must be a prime number (PHP will round up if it isn't). For Magento 2, count your PHP files:

find /var/www/html -name "*.php" | wc -l
Enter fullscreen mode Exit fullscreen mode

A typical Magento installation with common extensions has 15,000–30,000 PHP files. Set this to 65407 to be safe — the memory overhead is negligible.

opcache.validate_timestamps=0

This is the biggest production win. When set to 0, PHP never checks disk to see if a file has changed — it trusts the cache completely. This eliminates a stat() syscall per file per request.

The catch: you must manually reset OPcache on every deployment. Add this to your deploy script:

php bin/magento cache:flush
# Reset OPcache via PHP-FPM reload or:
kill -USR2 $(cat /var/run/php/php8.2-fpm.pid)
Enter fullscreen mode Exit fullscreen mode

Or use cachetool for a zero-downtime OPcache reset:

cachetool opcache:reset --fcgi=127.0.0.1:9000
Enter fullscreen mode Exit fullscreen mode

opcache.save_comments=1

Do not set this to 0 for Magento. Magento's dependency injection framework relies on PHPDoc annotations (like @param, @return, and custom annotations) to resolve types. Disabling comment saving will break DI resolution and cause cryptic errors.

opcache.interned_strings_buffer

PHP interns (deduplicates) strings across all cached scripts. Class names, method names, and string literals get stored once. The default 8MB is too small for Magento — bump it to 64MB.

PHP 8 JIT: Worth Enabling for Magento?

PHP 8.0+ includes a Just-In-Time compiler. For CPU-bound workloads like number crunching, JIT is transformative. For I/O-bound web apps like Magento... it's more nuanced.

In practice:

  • JIT provides minimal gains for typical Magento page loads (DB and I/O are the bottleneck, not CPU)
  • JIT can provide meaningful gains for catalog price rule recalculation, mass product imports, and CLI operations
  • JIT adds memory overhead and some compilation latency on first execution

Recommendation: Enable JIT on PHP 8.1+ production servers and benchmark your specific workload.

opcache.jit=1255
opcache.jit_buffer_size=128M
Enter fullscreen mode Exit fullscreen mode

1255 is the recommended mode: tracing JIT, which profiles at runtime and compiles hot code paths.

Deployment Workflow with OPcache

The most common OPcache mistake on Magento is forgetting to reset it after deployment. When validate_timestamps=0, your new files are on disk but PHP is still serving the old cached bytecode.

A complete deploy sequence:

# 1. Deploy new files
git pull origin main

# 2. Magento setup
php bin/magento setup:upgrade --keep-generated
php bin/magento setup:di:compile
php bin/magento setup:static-content:deploy -f

# 3. Clear Magento cache
php bin/magento cache:flush

# 4. Reset OPcache (choose one method)

# Method A: Reload PHP-FPM (brief interruption)
systemctl reload php8.2-fpm

# Method B: cachetool (zero-downtime)
cachetool opcache:reset --fcgi=/run/php/php8.2-fpm.sock

# Method C: Via web endpoint (if server allows)
curl https://yourstore.com/opcache-reset.php  # delete after use!
Enter fullscreen mode Exit fullscreen mode

OPcache with Multiple PHP Versions or Docker

If you run multiple PHP versions (e.g., PHP 7.4 and PHP 8.2 side-by-side), each PHP-FPM pool has its own separate OPcache. Configure each independently.

In Docker environments, OPcache shared memory lives inside the container. Key considerations:

  • Set opcache.memory_consumption appropriate to the container's memory limit
  • On container restart, OPcache is cleared automatically — no extra steps needed
  • Consider using opcache.file_cache as a warm-start mechanism between container restarts

Verifying Your Configuration

After applying changes, reload PHP-FPM and verify:

php -i | grep opcache

# Check memory usage in real time
watch -n 2 'php -r "print_r(opcache_get_status()[\"memory_usage\"]);"'
Enter fullscreen mode Exit fullscreen mode

Run a quick before/after benchmark with Apache Bench or wrk:

# Before (disable OPcache temporarily)
ab -n 100 -c 5 https://yourstore.com/

# After (with tuned OPcache)
ab -n 100 -c 5 https://yourstore.com/
Enter fullscreen mode Exit fullscreen mode

You should see a meaningful drop in requests-per-second time and TTFB.

Quick Reference: Production Checklist

Setting Recommended Value Why
opcache.enable 1 Obviously
opcache.memory_consumption 512 Magento needs it
opcache.max_accelerated_files 65407 Cover all Magento files
opcache.interned_strings_buffer 64 Avoid string pool exhaustion
opcache.validate_timestamps 0 No disk I/O per request
opcache.revalidate_freq 0 Irrelevant when timestamps disabled
opcache.save_comments 1 Required for Magento DI
opcache.optimization_level 0x7FFEBFFF Max optimization
opcache.jit 1255 (PHP 8+) JIT tracing mode
opcache.jit_buffer_size 128M Buffer for JIT compilation

Conclusion

OPcache is one of those rare optimizations that costs almost nothing to configure but pays dividends on every single request. For Magento 2 — a framework that loads hundreds of PHP files per page — getting OPcache right is non-negotiable.

The most impactful changes are:

  1. Increase memory_consumption — don't let the cache evict files under load
  2. Set validate_timestamps=0 — eliminate stat calls in production
  3. Reset OPcache on every deploy — or you'll serve stale bytecode

Tune these, benchmark your store, and you'll likely see significant improvements in TTFB and CPU usage without touching a single line of application code.

Top comments (0)