Your Laravel App is STILL Using PHP-FPM?!
Wake Up, Laravel! Ditch PHP-FPM for True Performance in 2026
The year is 2026. If your high-traffic Laravel application is still limping along on php-fpm, it’s time for a serious architectural intervention. The days of php-fpm being the default for serious scale are long past. While it served us well, its stateless, request-per-process model introduces significant overhead for modern, high-throughput applications. Every incoming request means re-bootstrapping your entire Laravel application – loading framework files, re-establishing database connections, re-parsing environment variables. This constant re-initialization eats up precious CPU cycles, inflates response times, and skyrockets your cloud bill.
It’s time to embrace the future: persistent application servers. Solutions like RoadRunner and FrankenPHP are not just optimizations; they are a fundamental shift in how your PHP application operates. By running your Laravel application within a persistent worker, the application boots once and then intelligently handles subsequent requests without re-initialization. Couple this with PHP 8.3/8.4’s JIT compiler, and you’ll witness boot times vanish, yielding a staggering 3-5x throughput boost. This isn’t about micro-optimizations; it’s architectural surgery that delivers shared state, persistent memory, and a dramatically leaner runtime. Your users will experience lightning-fast responses, and your infrastructure costs will plummet.
Architectural Shift: Integrating RoadRunner with Laravel
Transitioning to a persistent application server like RoadRunner is a straightforward, yet impactful, process. Here’s a walkthrough of how you’d typically set it up for your Laravel application:
1. Installation
First, pull in the RoadRunner core and the Laravel specific package:
composer require spiral/roadrunner spiral/roadrunner-laravel
Then, download the RoadRunner binary (it’s a Go executable that orchestrates your PHP workers):
./vendor/bin/rr get
This command fetches the appropriate rr binary for your operating system.
2. Configuration: The rr.yaml Layout
RoadRunner is configured via a simple rr.yaml file at the root of your project. This file dictates how RoadRunner listens for requests and how it manages your PHP workers.
# .rr.yaml
http:
address: 0.0.0.0:8000 # RoadRunner listens on this port
# ... other HTTP middleware/settings if needed
php:
bin: php # Path to your PHP binary (e.g., /usr/local/bin/php)
workers:
command: "php public/index.php" # The entry point for your persistent Laravel worker
pool:
num_workers: 4 # Number of PHP workers to keep alive
max_requests: 5000 # Restart a worker after 5000 requests to prevent memory leaks
# debug: true # Uncomment for verbose logging during development
Understanding the command: "php public/index.php":
Unlike php-fpm where public/index.php is executed per request, with RoadRunner, this command is executed once per worker. The spiral/roadrunner-laravel package then takes over, intercepting requests and managing the Laravel application lifecycle (resetting singletons, flushing state, etc.) between requests within that persistent worker. This is the magic that eliminates repeated bootstrapping.
3. Laravel Worker Configuration
The spiral/roadrunner-laravel package provides an application kernel specific for RoadRunner. You’ll typically configure this via a provider or by directly using the Rr facade within public/index.php (though the package usually handles most of this transparently). It intelligently resets global state and container bindings after each request, ensuring your application remains clean and predictable.
4. Running Your Application
With the rr.yaml in place, starting your server is as simple as:
./rr serve
RoadRunner will now start, spin up your specified number of PHP workers, and begin serving requests.
Brief Alternative: FrankenPHP
For those prioritizing simplicity and a single binary deployment, FrankenPHP is an excellent choice. It’s a Caddy server distribution with PHP embedded, meaning your entire server and PHP runtime can be compiled into a single executable. This is particularly powerful for Docker environments. A basic Dockerfile might look like:
# Dockerfile (FrankenPHP)
FROM dunglas/frankenphp
WORKDIR /app
COPY . /app
# Expose the port Caddy/FrankenPHP listens on
EXPOSE 80
# The default command will run Caddy/FrankenPHP
# with your Laravel application as the entrypoint.
FrankenPHP simplifies deployment by abstracting away the worker management, offering built-in HTTP/2, HTTPS (via Caddy), and even Mercure support out-of-the-box.
Conclusion: Embrace the Future, Today
Staying with php-fpm for high-traffic Laravel applications in 2026 is akin to driving a Formula 1 car with a carburetor – it fundamentally limits your potential. Persistent application servers like RoadRunner and FrankenPHP are not just about “some” performance gain; they represent an architectural paradigm shift that brings PHP applications into the same league as Node.js or Go services in terms of request handling efficiency. With persistent memory, shared state, and the raw speed of PHP 8.3/8.4’s JIT, you’re not just optimizing; you’re future-proofing your application. Stop wasting cycles, slash your cloud costs, and deliver an unparalleled user experience. The future of Laravel performance is here; it’s time to embrace it.