What Is OPcache? The Beginner's Guide (PHP Bytecode Caching, Explained)
CodexFuse Team · 2026-11-04T06:40:56.373Z · 11 min read min read
If your WordPress site feels sluggish even though your server has plenty of headroom, the culprit might not be your theme or your plugins. It might be that PHP is re-reading and re-compiling your code on every single request. OPcache is the built-in PHP feature that fixes exactly that: it stores PHP's precompiled script bytecode in shared memory, so the engine skips the load-and-parse step on every request.
This guide explains what OPcache is, how the bytecode-caching cycle works, how to check whether it is running on your server, and which settings are actually worth touching. If you run PHP on a self-hosted server, the VPS hosting guide pairs well with this one, and if your goal is a faster WordPress site overall, start with the WordPress speed guide to measure first and fix in the right order.
What Is OPcache, Exactly?
The PHP manual's own definition is the cleanest one available:
"OPcache improves PHP performance by storing precompiled script bytecode in shared memory, thereby removing the need for PHP to load and parse scripts on each request."
In plain English: PHP is an interpreted language. If you want OPcache explained in one sentence — it trades a little server memory for never compiling the same PHP file twice. Normally, when a visitor opens a page, PHP reads each .php file as text, parses it, compiles it into low-level instructions called opcodes, and then executes them. Without OPcache, that whole pipeline runs again for every request, even though the files have not changed. OPcache compiles each file once, keeps the resulting opcodes in a shared-memory segment, and serves them directly to every later request.
OPcache has been bundled with PHP since version 5.5.0 (it was available as a PECL package for PHP 5.2 through 5.4), so on any modern PHP version — the current stable is PHP 8.5.12, released 21 October 2026 — it is already on your server. It loads as a Zend extension, typically with a line like zend_extension=/usr/lib/php/20240924/opcache.so in your PHP configuration.
How Does OPcache Work? The 4-Step Cycle
Understanding the cycle makes every later setting make sense. Here is what happens on a request-by-request basis:
- First request: parse and compile. PHP reads the source file from disk, parses the human-readable code, and compiles it into opcodes (for example,
$a + $bbecomes an ADD instruction with two operands). The request is then executed normally. - Store. OPcache saves those compiled opcodes into a shared-memory segment. The size of that segment is controlled by
opcache.memory_consumption(default: 128 megabytes). - Later requests: skip straight to execution. When the next visitor hits the same file, PHP finds the compiled opcodes already in memory and runs them — no disk read, no parsing, no compilation.
- Change detection. If the source file changes, OPcache re-compiles it on the next check — unless you have disabled timestamp validation for production speed, in which case you must reset the cache yourself (more on that below).
The key detail is that the memory is shared: under PHP-FPM, the master process owns the segment and all worker processes reuse the same compiled code, so the benefit is not limited to a single execution. One compile serves every worker.
How Do I Check If OPcache Is Enabled?
There are three reliable ways to check, depending on what access you have:
- From the command line: run
php -mand look for the Zend extension in the modules list, or runphp --ri opcacheto print the extension's full configuration and current values. - From a script: create a file with
<?php phpinfo();and open it in your browser. The Zend OPcache section shows whether it is enabled along with every setting and its current value. Delete the file when you are done — leaving phpinfo exposed is a security risk. - Programmatically: call
opcache_get_status()from a script served by your web server (not from the CLI — the command-line and web SAPIs use separate caches, a gotcha covered below). It returns an array with keys likeopcache_enabled,memory_usage(used, free, and wasted memory),opcache_statistics(includinghits,misses, andopcache_hit_rate), andnum_cached_scripts.
Reading your hit rate is the single best health check. Compute it as hits / (hits + misses) — a healthy production site should sit above 90%, and in most real environments you will see something closer to 99%. If your hit rate is much lower, the cache is either too small or scripts are being churned out faster than they are reused.
How Should I Configure OPcache for WordPress?
WordPress is the most common place beginners meet OPcache: a single page load can touch hundreds of PHP files from core, your theme, and your plugins. A sensible OPcache WordPress configuration starts with the block the PHP manual itself recommends:
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.enable_cli=1
Those are the manual's own recommended values (plus opcache.fast_shutdown=1 only on PHP versions older than 7.2.0). On a busy WordPress site you will often want to raise two of them: memory_consumption to 256 and max_accelerated_files to 20000, because a stock WordPress install with several plugins can exceed the defaults. If you are setting WordPress up for the first time, the install WordPress walkthrough covers the server side, and what WordPress is explains the architecture these settings are accelerating.
One note for shared-hosting users: on many hosts OPcache is enabled by default, but not all — some hosting control panels let you toggle it under the PHP version settings for your account. If your host does not offer the toggle, that is a sign you have outgrown shared hosting for performance work.
Which OPcache Settings Actually Matter?
The manual documents dozens of directives, but five do almost all the work in practice:
| Setting | Default | What it does |
|---|---|---|
opcache.memory_consumption | 128 | Size of the shared-memory cache in megabytes. When it fills up, OPcache stops caching new files — on WordPress, raise it to 256 before anything else. |
opcache.interned_strings_buffer | 8 | Memory for interned strings (class names, variable names reused across files) in megabytes. Raise to 16 on large codebases. |
opcache.max_accelerated_files | 10000 | Maximum number of scripts the cache table can hold. The engine rounds your value up to the next prime from its internal set (223, 463, 983, 1979, …). Raise it if num_cached_scripts from opcache_get_status() keeps hitting the ceiling. |
opcache.validate_timestamps | 1 | When on, OPcache re-checks file timestamps every opcache.revalidate_freq seconds. In production, where files never change outside a deploy, turning this off removes the check overhead — but you must then reset the cache after every deploy. |
opcache.revalidate_freq | 2 | How often timestamp checks run, in seconds. Zero means check on every request. Largely irrelevant once you disable timestamp validation. |
Two settings that surprise beginners: opcache.enable cannot be turned on at runtime with ini_set() — it can only be disabled that way, and trying to enable it generates a warning. And opcache.enable_cli defaults to 0, which means the CLI binary runs without an opcode cache unless you opt in — relevant to the gotcha in the next section.
OPcache vs Page Cache vs Object Cache: What's the Difference?
This is the single most common point of confusion. These are three separate layers, and they cache three different things:
| Layer | What it caches | Example |
|---|---|---|
| OPcache (opcode cache) | Compiled PHP bytecode in shared memory — skips parsing and compiling, but PHP still executes your application logic on every hit | PHP's built-in OPcache |
| Page cache | Full HTTP responses — the server skips PHP entirely and serves stored HTML | Varnish Cache, which "sits between clients and your origin servers" and "answers from its in-memory cache when it can" |
| Object cache | Data: database query results, API responses, rendered fragments — key-value storage your code reads and writes explicitly | Memcached, "an in-memory key-value store for small chunks of arbitrary data"; or Redis, "an in-memory data structure store" |
The practical takeaway: enabling OPcache does not replace a page cache or an object cache, and a page cache does not replace OPcache. A fast PHP stack usually runs all three, because each one removes a different chunk of work — compiling code, executing code, and re-fetching data.
What Are the Common OPcache Gotchas?
Three traps catch almost everyone eventually:
The "my deploy didn't take effect" trap
If you disable timestamp validation for production speed (opcache.validate_timestamps=0), OPcache will never notice that your files changed. The PHP manual states you must then "reset OPcache manually via opcache_reset(), opcache_invalidate() or by restarting the Web server for changes to the filesystem to take effect." Symfony's performance guide makes the same point: disable the timestamp checks in production to avoid the overhead, but always empty and regenerate the cache after each deployment. Note that opcache_reset() only resets the in-memory cache, not the secondary file cache if you have opcache.file_cache enabled.
The "I cleared it from the terminal" trap
The CLI and the web processes do not share the same OPcache. Running opcache_reset() or a cachetool command from your terminal clears only the CLI cache — your visitors are still being served the old compiled code. To reset the web cache, restart the web server, or expose a small script served over HTTP that calls opcache_reset() (protect it behind authentication).
The "cache is full and I didn't notice" trap
When the shared-memory segment fills up, OPcache simply stops caching new files. Watch wasted_memory and free_memory in opcache_get_status(): if free memory is near zero and your hit rate drops below the ~90% healthy line, increase memory_consumption. Also useful: opcache_compile_file() compiles and caches a script without executing it, which lets you prime the cache with your most-hit files right after a server restart instead of waiting for visitors to warm it.
Should You Worry About JIT and Preloading?
Probably not yet — but it helps to know where they sit. Preloading (available since PHP 7.4) compiles and executes a script at server startup so its classes and functions are permanently available; think of it as OPcache starting warm. JIT (available since PHP 8.0) goes further and compiles hot code paths to native machine code at runtime, where OPcache itself only removes the parse-and-compile step. One fact worth knowing: as of PHP 8.4.0 the JIT default changed from tracing to disable, with a default opcache.jit_buffer_size of 64M. For a typical WordPress site, a well-tuned OPcache is the win that matters; JIT and preloading are optimizations for the road after that.
Sources
- PHP Manual, "Introduction" to OPcache — definition of OPcache, bundled-with-5.5.0 and PECL history: https://www.php.net/manual/en/intro.opcache.php
- PHP Manual, OPcache installation — zend_extension loading, recommended php.ini values: https://www.php.net/manual/en/opcache.installation.php
- PHP Manual, OPcache runtime configuration — all directive defaults and descriptions quoted in this article: https://www.php.net/manual/en/opcache.configuration.php
- PHP Manual, opcache_get_status() — return structure and key names: https://www.php.net/manual/en/function.opcache-get-status.php
- PHP Manual, opcache_reset() — in-memory-only reset semantics: https://www.php.net/manual/en/function.opcache-reset.php
- PHP Manual, opcache_compile_file() — cache priming: https://www.php.net/manual/en/function.opcache-compile-file.php
- PHP Manual, command-line options — php -m / php --ri: https://www.php.net/manual/en/features.commandline.options.php
- Symfony Performance guide — timestamp-check advice and CLI/web cache separation: https://symfony.com/doc/current/performance.html
- PHP.net front page — PHP 8.5.12 release (21 October 2026) and 8.2 end-of-life date: https://www.php.net/
- Codana, "PHP OPCache, Realpath Cache & Preloading" — shared-memory semantics, hit-rate guidance: https://www.codana.be/en/insights/php-opcache-realpath-cache-preloading
- FXRM blog, "WordPress Performance Is a Server Problem" (2 days old) — WordPress OPcache sizing example: https://blog.fxrm.com/wordpress-performance-opcache-object-cache-php-fpm/
- Pagely blog, "Cache, CDN, and plugin conflicts" (9 days old) — WP-CLI vs PHP-FPM OPcache separation: https://pagely.com/blog/cache-cdn-and-plugin-conflicts-why-client-changes-dont-appear-on-your-wordpress-site/
- Varnish Cache, varnish-cache.org — page-cache layer definition
- Memcached, memcached.org — object-cache layer definition
- Redis, redis.io — data-store cache definition
Frequently Asked Questions
Is OPcache enabled by default in PHP?
OPcache is bundled with every PHP version since 5.5.0, and the opcache.enable default is 1 — but whether it is actually active depends on your server's configuration, because the extension still has to be loaded via zend_extension. Check with php -m or php --ri opcache; on shared hosting you may need to enable it in your control panel's PHP settings.
Do I need OPcache if I use a caching plugin like WP Rocket?
Yes. Caching plugins and CDNs typically handle the page-cache layer (storing full HTML responses), while OPcache handles the opcode layer (skipping PHP parsing and compilation). They remove different work, so a fast site runs both.
Will OPcache speed up my WordPress site?
OPcache removes the parse-and-compile step for every PHP file, and a WordPress page load touches hundreds of them — so it consistently reduces server-side response time on any PHP application, WordPress included. It does not replace page caching or object caching; the biggest wins come from running all three layers.
Why do my code changes not show up after deploying?
Almost always this is timestamp validation. If opcache.validate_timestamps is disabled in production (the recommended setup), OPcache never re-checks your files — you must reset the cache with opcache_reset(), invalidate the changed files, or restart the web server after each deploy. And remember: resetting from the CLI does not touch the web server's cache.
Is OPcache the same as the JIT compiler in PHP 8?
No. OPcache caches compiled bytecode so PHP skips re-parsing your code; the JIT compiler (available since PHP 8.0) goes a step further and compiles hot code paths to native machine code at runtime. JIT builds on top of OPcache — and since PHP 8.4.0 it is disabled by default, so OPcache alone is the standard performance setup.

