The FrankenPHP runtime
Your WordPress sites run on FrankenPHP, a modern PHP application server built on the Caddy web server, instead of the legacy php-fpm setup most managed hosts still ship. Both the bedrock and vanilla profiles are served this way; you don’t configure it and you don’t opt in — it’s the default and only WordPress runtime. This page explains what that buys you and the handful of things worth knowing about it.
What’s different from php-fpm
Section titled “What’s different from php-fpm”The classic stack is Nginx or Apache in front of php-fpm: a pool of worker processes, each of which boots the full WordPress bootstrap — autoloaders, plugins, config — on every single request, then throws it all away. FrankenPHP changes the shape of that in three ways.
- Worker mode. FrankenPHP boots WordPress once and keeps the application resident, serving many requests from an already-warm process. The expensive bootstrap stops being per-request, which is where most of the latency win comes from.
- One process, no FastCGI hop. The web server and the PHP runtime are the same process. There’s no FastCGI socket between Caddy and a separate php-fpm pool, so there’s less per-request overhead and fewer moving parts to tune.
- Higher throughput at the same resources. Because the bootstrap is amortized and the hop is gone, the same environment serves more requests per second. Exact throughput gains vs php-fpm are workload-dependent.
Worker mode and your code
Section titled “Worker mode and your code”Worker mode is where the speed comes from, and it’s also the one thing to keep in mind when you write or evaluate code. Because the WordPress process stays resident across requests, global and static state persists between requests in the same worker. Well-behaved plugins and themes don’t depend on a fresh process per request, so the vast majority run unchanged. A few patterns are worth checking:
- Don’t rely on process death to clean up. Code that leaks into PHP globals or static properties and assumes a per-request reset can accumulate state across requests. Reset what you set.
- Watch long-lived resources. A connection or handle opened at bootstrap and never closed lives for the worker’s lifetime, not a single request.
- Avoid
exit/diein normal request flow. Hard process termination is a php-fpm habit; in worker mode it’s heavier-handed than returning a response.
How it interacts with the cache
Section titled “How it interacts with the cache”FrankenPHP and the built-in cache are complementary layers, not competitors:
- The full-page cache sits in front of the runtime. A cache hit is served without invoking WordPress at all, so worker mode’s warm process is only spent on requests that actually need PHP — cache misses, logged-in users, and dynamic endpoints.
- The persistent object cache lives behind the runtime, so the queries and transients a cache miss does run are backed by a shared, persistent store rather than rebuilt from the database each time.
Together that means the fast path skips PHP entirely, and the slow path runs on a warm, object-cache-backed process. See caching for what’s cached, what’s bypassed, and how to purge.
Seeing the effect
Section titled “Seeing the effect”The latency improvement shows up directly in your performance data — request timings and p95 latency in observability are measured against the FrankenPHP runtime, so the warm-process effect is visible in the numbers rather than just asserted here.