Enabling and tuning PHP OpCache for faster executionfor Drupal 11 , 10 , 9 , and 8

Last updated :  

Without OpCache, PHP re-parses and re-compiles every single .php file on every single request — Drupal alone loads hundreds of files per page. OpCache stores the compiled bytecode in shared memory after the first request, so every subsequent request skips parsing entirely. This is the single highest-impact PHP-level setting on any Drupal site, and it's disabled or misconfigured surprisingly often.

What you'll learn in this lesson

  • The two settings that matter most: memory allocation and timestamp validation
  • Why validate_timestamps=0 is a production-only setting
  • How to confirm OpCache is actually working, not just enabled

The settings that matter

; php.ini or a dedicated opcache.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=0

memory_consumption (in MB) is the shared-memory pool OpCache stores compiled files in — too small, and it starts evicting cached files under load, silently losing the benefit. max_accelerated_files needs to comfortably exceed your actual file count; Drupal core plus a typical set of contrib modules easily passes 15,000-20,000 PHP files.

The production-only setting

; Production only — NEVER on a development environment.
opcache.validate_timestamps=0
The gotcha that costs people hours of confusion: with validate_timestamps=0, OpCache stops checking whether a .php file's modification time has changed — meaning it keeps serving the OLD compiled version even after you deploy new code, until the OpCache is explicitly reset (a PHP-FPM reload, typically part of a proper deploy script). On a local dev environment this makes every code change appear to do nothing. Only set it to 0 on production, paired with a deploy process that reloads PHP-FPM after every deploy.

Confirming it's actually working

// A quick one-off check via drush or a temporary script:
var_dump(opcache_get_status()['opcache_statistics']);
// Look at 'hits' vs 'misses' — a healthy production site should show
// hits vastly outnumbering misses once warmed up.

Quick check: you deployed new code to production, but the site keeps behaving like the old version. Cache clear didn't help. What's the most likely OpCache-related cause? If you said validate_timestamps=0 is set and PHP-FPM was never reloaded after deploy, you've got the classic version of this exact problem.

Key takeaways

  • OpCache eliminates PHP's re-parse-and-compile cost on every request — the single highest-impact PHP setting for Drupal.
  • Size memory_consumption and max_accelerated_files generously enough that OpCache never has to evict cached files under normal load.
  • validate_timestamps=0 is a real production performance win, but requires a deploy process that reloads PHP-FPM afterward.
  • Check opcache_get_status()'s hit/miss ratio to confirm it's actually helping, not just enabled.

Coming up next

OpCache speeds up how fast PHP itself runs. Next, we look at PHP-FPM — the process manager that decides how many of those fast PHP requests can run at once.