Which PHP Runtime Delivers the Best Performance for Symfony? Benchmark Results
A comprehensive benchmark compares multiple PHP runtimes—including Apache, Nginx, Nginx Unit, Roadrunner, FrankenPHP, and Swoole—under identical Docker‑based test conditions using k6 load testing, revealing significant performance differences and offering practical recommendations for Symfony applications.
Test Environment
Each runtime is executed in one or two Docker containers.
Each container is limited to 1 CPU core and 1 GB of RAM.
The load‑testing client (k6) runs in the same Docker network as the containers under test.
Tested Application
Symfony’s runtime component extracts bootstrap logic from global state, allowing the same application code to run on any PHP runtime while preserving production‑grade performance. The benchmark therefore compares classic PHP‑FPM stacks with alternative runtimes such as Swoole, AMPHP, ReactPHP, RoadRunner, FrankenPHP and Nginx Unit.
Load‑Testing Tool
The k6 tool generates HTTP traffic. For each runtime three separate runs are performed: 10, 100 and 1 000 concurrent virtual users, each lasting 30 seconds. Metrics collected include total requests served and request latency.
Runtimes Evaluated
Apache (prefork) + mod_php
Apache (event) + PHP‑FPM
Nginx + PHP‑FPM
Nginx Unit application server
Nginx + RoadRunner (fcgi mode)
RoadRunner (native mode)
FrankenPHP (standard mode)
FrankenPHP (worker mode)
Swoole (with Symfony runtime bundle)
All runtimes are built from official Docker images. When an official image does not exist, the application source is copied into a base image during the Docker build. PHP 8.3 is used everywhere except Nginx Unit, which supports up to PHP 8.2 as of early 2024. Compatible ReactPHP and AMPHP images for Symfony 7 were not found, and the PHPPM project appears abandoned.
PHP and Symfony Configuration
Base php.ini‑production from the official Docker image.
Opcache enabled with default settings.
JIT compilation enabled.
Preload script configured according to Symfony best practices.
Composer autoloader optimized ( composer dump‑autoload -o).
Symfony executed in prod environment.
Service container compiled into a single PHP file.
Symfony cache warmed during the Docker image build.
Full source code, Dockerfiles and configuration files are available at https://github.com/DimDev/php-runtimes-benchmark.
Results
Apache + mod_php (001) and Apache + PHP‑FPM (002) produce virtually identical throughput.
Nginx + PHP‑FPM (003) matches the Apache stacks at low load (10 – 100 concurrent users).
At 1 000 concurrent users, Nginx + PHP‑FPM serves roughly twice as many requests as the Apache configurations.
Nginx Unit (004) is about three times faster than the traditional Nginx + PHP‑FPM stack.
RoadRunner in fcgi mode (005) and native mode (006) show similar performance, both more than twice as fast as Nginx + PHP‑FPM.
FrankenPHP standard mode (007) performs on par with Nginx + PHP‑FPM.
FrankenPHP worker mode (008) achieves up to a 10× speedup over Nginx + PHP‑FPM at 1 000 concurrent connections, but cannot be started with php‑ini‑production.
Swoole (009) reaches comparable speeds to FrankenPHP worker mode; however, the application code must be adapted for Swoole and a Symfony bundle is required to integrate the runtime component.
Observations
FrankenPHP demonstrates a strong performance advantage and may become a new reference implementation for PHP runtimes.
Swoole offers a high‑performance extension but requires code modifications and additional Symfony integration.
Nginx Unit provides a lightweight, easy‑to‑configure server with excellent raw throughput, despite lacking HTTP/2 and some advanced Nginx features.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
