PHP 8.5 Application Server Selection Guide: FPM vs RoadRunner vs Swoole vs FrankenPHP (2026)

Choosing the right application server is one of the most important architectural decisions you can make in the PHP 8.5 era. It directly impacts your response times, throughput, operational complexity, and infrastructure costs.

Over the past year, we systematically benchmarked PHP-FPM, RoadRunner, Swoole, and FrankenPHP. This article is not about telling you “X is the best” – it gives you a practical, data‑driven decision framework, not marketing hype.


🧪 Our Testing Methodology

All data comes from two benchmark series:

Unified test conditions:

  • PHP: 8.5.7 (OPcache + JIT tracing, buffer 128M)
  • Workers: 20 parallel workers across all environments
  • Business logic: 1000 sqrt iterations + one SELECT 1 query (realistic CPU + I/O mix)
  • Load generator: ab -c 100 -t 60 (100 concurrent connections, 60 seconds), 3 runs per configuration
  • Server: 4 vCPU, 8 GB RAM, Ubuntu 22.04

We deliberately avoided testing simple echo "hello" endpoints. Real applications spend ~3% of their time on TCP transport and ~97% on database queries, caching, serialisation, middleware, and business logic. Our tests reflect production‑like workloads.


📋 Quick Overview of the Four Servers

PHP‑FPM (The Classic Baseline)

Architecture: Nginx + FastCGI process manager. Each request spawns a PHP process that dies after the request completes.

Pros:

  • Mature, stable, and available everywhere
  • Simple configuration; largest ecosystem
  • Process isolation – a single crashed request does not affect others

Cons:

  • Framework bootstrap is repeated on every request (Laravel/Symfony add 10–30 ms overhead each time)
  • Process count grows linearly with concurrency, consuming more memory
  • No connection pooling for databases or Redis

Best for: Traditional shared hosting, low‑concurrency applications, and scenarios where stability is the top priority.

RoadRunner (Go‑powered High‑Performance Server)

Architecture: Go application server that communicates with PHP workers via a pipes protocol. PHP processes stay resident in memory; the framework loads only once.

Pros:

  • Eliminates framework bootstrap overhead; QPS can be 10–50× higher than FPM
  • Rich plugin ecosystem (HTTP, gRPC, queues, etc.)
  • More stable and resource‑efficient than Swoole in containerised environments
  • PSR‑7 compatible – smooth migration from existing code

Cons:

  • Requires an extra Go binary and a configuration file (.rr.yaml)
  • Slight PSR‑7 serialisation overhead in pure CPU‑bound scenarios (Article #18: FPM 2979 RPS vs RoadRunner 2591 RPS)

Best for: API services, microservices, containerised deployments, and teams wanting a gradual migration path from FPM.

Swoole (PHP Extension, Coroutine King)

Architecture: C++ PHP extension providing asynchronous I/O and coroutines. PHP processes stay resident and handle requests through an event loop.

Pros:

  • Highest bare‑metal performance: Article #18 shows Swoole + tracing JIT hits 4981 RPS (1.67× FPM)
  • Coroutine support keeps RPS almost flat under I/O latency (50 ms / 200 ms delays still deliver ~5000 RPS)
  • Supports WebSocket, TCP/UDP, and microservice‑oriented features
  • OpenSwoole 26.2.0 now supports PHP 8.5 and io_uring

Cons:

  • Largest Docker performance loss (Article #20: bare metal 4981 → Docker bridge 2012, a 60% drop)
  • Requires code adaptation (coroutine safety, avoiding global state)
  • PHP extension installation adds complexity in some environments
  • Process instability was an issue with earlier versions (PHP 8.5 requires the latest Swoole releases)

Best for: High‑performance APIs, real‑time WebSocket applications, latency‑sensitive services, and teams willing to invest in code refactoring.

FrankenPHP (Caddy‑embedded, The Rising Star)

Architecture: Go application server that embeds the PHP interpreter directly into the Caddy web server. A single binary runs the entire application – no Nginx, no PHP‑FPM.

Pros:

  • Extremely simple deployment: one binary for everything
  • Worker mode delivers huge gains – throughput can be 3–5× higher than FPM by eliminating framework bootstrap
  • Classic mode works as a drop‑in replacement for FPM
  • Built‑in automatic HTTPS and HTTP/3 support from Caddy
  • Officially supported by Laravel Octane

Cons:

  • JIT is incompatible with Worker mode (ZTS limitation) – FrankenPHP’s worker model uses Zend Thread Safety, which conflicts with PHP’s JIT
  • Relatively new; fewer production case studies than RoadRunner
  • Plugin ecosystem is less mature than RoadRunner’s

Best for: Greenfield projects, teams that want zero‑configuration deployment, applications that do not depend heavily on JIT, and those seeking operational simplicity.


📊 Bare‑Metal Performance (tracing JIT, 20 workers)

FrankenPHP data is based on public benchmarks; it was not included in our JIT test matrix due to the ZTS limitation.

Environment0ms I/O (RPS)50ms I/O (RPS)200ms I/O (RPS)P99 (0ms)Memory
PHP‑FPM29793889855msLow (per‑request)
RoadRunner25912664254273msMedium
Swoole49815008506062msMedium‑High
FrankenPHP~3000‑5000*Medium

*FrankenPHP classic mode performs similarly to FPM; worker mode can deliver 3–5× FPM throughput on framework‑based applications.

Bar chart comparing RPS of PHP-FPM, RoadRunner, Swoole, and FrankenPHP on bare metal under 0ms, 50ms, and 200ms I/O delay
Figure 1: Bare‑metal RPS comparison – Swoole leads, FPM collapses under I/O latency.

Key takeaways:

  • Swoole is the performance leader on bare metal and stays almost flat under I/O latency.
  • RoadRunner and FrankenPHP heavily outperform FPM in I/O‑heavy scenarios thanks to persistent workers and connection pools.
  • FPM degrades catastrophically under I/O latency (98 RPS at 200ms).
Line chart illustrating RPS degradation of PHP-FPM, RoadRunner, Swoole, and FrankenPHP as I/O latency increases
Figure 2: Performance degradation under I/O latency – FPM drops sharply; Swoole stays flat.

🐳 Docker Performance Impact (from Article #20)

EnvironmentBare Metal RPSDocker Bridge RPSDocker Host + CPU Pin RPS
PHP‑FPM29791944 (-35%)5543 (+86%)
RoadRunner25911230 (-53%)2838 (+9%)
Swoole49812012 (-60%)9700 (+95%)
Bar chart showing Docker vs bare metal performance for PHP-FPM, RoadRunner, and Swoole with bridge network and host network plus CPU pinning
Figure 3: Docker impact – bridge mode penalises all three; host + CPU pinning recovers and even exceeds bare metal for PHP‑FPM and Swoole.

Key takeaways:

  • Default Docker bridge network imposes a 35–60% performance penalty on all environments.
  • --network host + CPU pinning fully eliminates the Docker overhead and even exceeds bare‑metal performance in some cases.
  • Swoole is the most sensitive to Docker networking, but also reaps the biggest reward from optimisation (9700 RPS – 195% of bare metal).

🎯 Decision Framework: Which One Should You Choose?

Step 1 – Characterise Your Application

Application ProfileRecommended ServerWhy
Traditional CMS / Shared HostingPHP‑FPMMost compatible; no extra setup
API Service (I/O‑heavy)RoadRunner or FrankenPHPPersistent workers + connection pools
WebSocket / Real‑timeSwooleNative coroutines + WebSocket support
Microservices / ContainerisedRoadRunnerMost stable and resource‑efficient in containers
Greenfield / Operational SimplicityFrankenPHPSingle‑binary deployment; automatic HTTPS
Maximum Bare‑Metal PerformanceSwooleHighest RPS and coroutine I/O
Gradual Migration from FPMRoadRunnerPSR‑7 compatible; minimal code changes

Step 2 – Evaluate Your Constraints

ConstraintRecommendation
Must use DockerAvoid Swoole (biggest loss); prefer RoadRunner or FrankenPHP; always use --network host
Must enable JITAvoid FrankenPHP Worker mode (ZTS conflicts); prefer Swoole or RoadRunner
High code‑change costPrefer RoadRunner or FrankenPHP (PSR‑7 compatible); Swoole requires coroutine adaptation
Limited ops experiencePrefer FrankenPHP (single binary) or PHP‑FPM (most familiar)

Step 3 – Decision Matrix

ScenarioPHP‑FPMRoadRunnerSwooleFrankenPHP
Traditional shared hosting
High‑concurrency API⚠️
WebSocket⚠️⚠️
Containerised deployment⚠️⚠️
Bare‑metal performance⚠️⚠️⚠️
JIT must be enabled⚠️*
Operational simplicity⚠️⚠️
Laravel / Symfony⚠️

* FrankenPHP Worker mode does not support JIT due to ZTS; classic mode works with JIT but offers limited performance gains.


📝 Summary Recommendations

  • If you are still on FPM and your application is I/O‑heavy: Migrate to RoadRunner or FrankenPHP. You can expect 5–20× performance gains.
  • If you need maximum bare‑metal performance: Swoole + tracing JIT on bare metal delivers 4981 RPS – the highest we have measured.
  • If you must run in Docker: Always use --network host + --cpuset-cpus. RoadRunner is the most stable choice in containers; Swoole gives the biggest improvement after tuning but requires more effort.
  • If you are using Laravel or Symfony: Octane supports all three (FrankenPHP, Swoole, RoadRunner). FrankenPHP is the easiest to set up, Swoole is the fastest, and RoadRunner is the most battle‑tested.
  • Do not obsess over JIT tuning: As Article #18 shows, JIT mode differences are under 5% within the same environment. The choice of server (FPM vs persistent‑worker) matters far more than JIT settings.
  • Always benchmark your own real application: Synthetic tests like echo "hello" are misleading. Use your actual routes, database queries, and caching logic to make the final decision.

Data sources: PHPBenchLab Article #18 (JIT mode comparison) and Article #20 (Docker vs bare metal). Full datasets, Dockerfiles, and benchmark scripts are available on GitHub.

Have you already migrated from FPM to a persistent server? Share your experience in the comments!

Published on June 21, 2026 – PHP 8.5 application server selection guide.

Leave a Comment