Bekzod Erkinov
Listen to Article
Loading...Laravel Octane Benchmark: FrankenPHP vs Swoole vs RoadRunner vs PHP-FPM
Most Octane benchmarks are a hello-world on hardware nobody describes. I ran the same Laravel app under PHP-FPM, FrankenPHP, Swoole and RoadRunner in Docker on one laptop, three runs per cell, then broke it on purpose in the ways Octane breaks apps. You get the numbers (laptop numbers, with their spread), every Dockerfile needed to rerun them, the failures with real output, and the fixes.
Laravel Octane benchmark setup
- App: fresh
laravel/laravelwithlaravel/octanev2.21.0, which the Octane releases page showed as the latest release (06 Oct) when I checked on 11 Oct 2026. Defaultwebmiddleware, array session and cache drivers, SQLite. - Versions as reported inside my containers (I did not cross-check them upstream): Laravel framework v13.35.0, PHP 8.4.26, FrankenPHP v1.13.1 (Caddy v2.11.7), Swoole 6.2.3, RoadRunner 2025.1.15, oha 1.16.0, Docker 29.7.2.
- Limits: every container ran with
--cpus=4 --memory=2gand 4 workers (FPM:pm = static,pm.max_children = 4). - Load: oha, 64 concurrent connections, 20 seconds after a 5-second warm-up, from a container on the same Docker network.
- Machine: a Windows 11 laptop, Docker Desktop reporting 8 CPUs and ~8 GB. The load generator shares the machine with the server, so treat absolute numbers as low and noisy.
Laravel Octane benchmark results: FrankenPHP vs Swoole vs RoadRunner vs PHP-FPM
Three runs per cell. Each cell is the median (min–max) of those three runs. All 24 runs had a 100% success rate.
/json (returns a small JSON body):
| Server | rps | p50 ms | p99 ms |
|---|---|---|---|
| PHP-FPM | 320 (273–383) | 177 (156–226) | 434 (351–459) |
| Swoole | 508 (400–538) | 103 (99–136) | 658 (656–784) |
| RoadRunner | 362 (252–400) | 150 (133–238) | 493 (372–658) |
| FrankenPHP | 534 (472–566) | 112 (108–136) | 232 (197–239) |
/db (a count() plus the latest 20 rows of a 1,000-row SQLite table):
| Server | rps | p50 ms | p99 ms |
|---|---|---|---|
| PHP-FPM | 237 (155–242) | 268 (246–416) | 614 (532–666) |
| Swoole | 366 (296–373) | 149 (148–163 |
Unlock Premium Content
You've read 30% of this article
What's in the full article
- Complete step-by-step implementation guide
- Working code examples you can copy-paste
- Advanced techniques and pro tips
- Common mistakes to avoid
- Real-world examples and metrics
Don't have an account? Start your free trial
Join 10,000+ developers who love our premium content
Keep reading
Complete Stripe Integration Template for Subscription-Based Services
29 min · 903 views
Operating SystemsAdvanced Laravel Tutorial: Queues, Events and Pest Tests
22 min · 239 views
PerformanceComplete Solution: Building a Secure E-commerce Website with Stripe and Laravel
28 min · 229 views
Bekzod Erkinov
AuthorFounder of NextGenBeing. Software engineer working with Laravel, Python, and cloud infrastructure. Writes about patterns that actually hold up in production. Based in Tashkent, Uzbekistan.
Get the AI-Assisted Developer's Field Guide
The workflow, prompts, and tools I use to ship faster with AI — free when you subscribe. Plus new deep-dives in your inbox. No spam, unsubscribe anytime.
Comments (0)
Please log in to leave a comment.
Log In