DEV Community

Cover image for PHP-FPM vs. Laravel Octane on Deploynix: Real-World Performance Comparison
Deploynix
Deploynix

Posted on • Originally published at deploynix.io

PHP-FPM vs. Laravel Octane on Deploynix: Real-World Performance Comparison

For over two decades, PHP-FPM has been the standard way to serve PHP applications. Nginx receives a request, passes it to PHP-FPM, a worker process boots the framework, handles the request, sends the response, and then the process either dies or resets for the next request. This model is reliable, well-understood, and the foundation of millions of production applications.

Laravel Octane changes the equation by keeping the Laravel application bootstrapped in memory between requests. Instead of booting the framework for every request, Octane boots once and then handles requests using a long-lived process. The result is dramatically reduced overhead per request, higher throughput, and lower latency.

But Octane is not a drop-in replacement for PHP-FPM. It introduces new constraints, requires attention to memory management, and is not compatible with all Laravel packages. This guide compares PHP-FPM and Octane across the three drivers Deploynix supports — FrankenPHP, Swoole, and RoadRunner — with benchmarks from real-world Laravel workloads.

How PHP-FPM Works

PHP-FPM (FastCGI Process Manager) manages a pool of worker processes. When Nginx receives a PHP request, it forwards the request to an available FPM worker via a Unix socket or TCP connection. The worker:

  1. Initializes the PHP runtime
  2. Boots the Laravel framework (service providers, middleware, routes, configuration)
  3. Handles the request
  4. Sends the response
  5. Resets its state for the next request

The framework boot process happens on every single request. For a typical Laravel application, this boot takes 10-30ms depending on the number of service providers and the complexity of the application. This overhead is invisible to users on fast servers, but at high concurrency it becomes a significant fraction of total processing time.

Memory model: Each FPM worker is an independent process with its own memory space. After each request, PHP's garbage collector cleans up all allocated memory. Memory leaks are impossible by design — even leaky code gets cleaned up at the end of the request.

Stability: PHP-FPM is battle-tested over two decades. It handles crashes gracefully (a crashed worker is replaced automatically), has no issues with memory leaks, and is compatible with every PHP library and Laravel package ever written.

How Laravel Octane Works

Octane starts a long-lived application server that boots Laravel once and then handles multiple requests without rebooting. The framework's service container, routes, configuration, and middleware are initialized at startup and shared across all subsequent requests.

When a request arrives:

  1. Octane clones the application container (a lightweight operation)
  2. The request is handled using the pre-booted framework
  3. The response is sent
  4. Request-specific state is cleaned up (but the base application stays in memory)

Memory model: The application stays in memory between requests. This is both the source of Octane's performance advantage and its primary constraint. If your application code stores state in static properties or singletons that are not properly reset between requests, state can leak from one request to another.

Application servers: Octane supports three underlying servers, each with different characteristics.

The Three Octane Drivers

FrankenPHP

FrankenPHP is a modern PHP application server built on top of the Caddy web server. It is written in Go and provides a worker mode that keeps PHP scripts in memory between requests.

Key characteristics:

  • Easy to set up — it is a single binary with no PHP extensions required
  • Supports early hints (HTTP 103) for faster page loads
  • Automatic HTTPS via Caddy's built-in Let's Encrypt integration
  • Worker mode provides Octane-compatible persistent processes
  • Actively developed with strong community support

Best for: Teams that want Octane performance with the simplest possible setup. FrankenPHP is the newest of the three drivers and has gained rapid adoption due to its ease of deployment.

Swoole

Swoole is a PHP extension written in C++ that provides asynchronous I/O and coroutine support. It has been the traditional high-performance choice for PHP applications.

Key characteristics:

  • Requires the Swoole PHP extension (compiled C++ code)
  • Supports coroutines for concurrent I/O within a single request
  • Built-in WebSocket server
  • Highest raw performance of the three drivers
  • Largest community among high-performance PHP runtimes

Best for: Applications that need maximum throughput and can benefit from coroutine-based concurrency (many external API calls, parallel database queries).

RoadRunner

RoadRunner is an application server written in Go that communicates with PHP workers via a binary protocol over pipes.

Key characteristics:

  • No PHP extension required — uses standard PHP with a Go-based process manager
  • Workers are standard PHP processes managed by the Go runtime
  • Supports gRPC, WebSockets, and job queues natively
  • Middleware and plugins written in Go

Best for: Teams that prefer not to install PHP extensions and want a Go-based process manager with broad feature support.

Benchmark Setup

To provide meaningful comparisons, we benchmarked on a Deploynix-provisioned server with the following specifications:

  • Provider: Hetzner
  • Server: CX32 (4 vCPU, 8GB RAM, NVMe SSD)
  • OS: Ubuntu 24.04 LTS
  • PHP: 8.4
  • Database: MySQL 8.4 (same server for consistency)
  • Cache: Valkey 8.0

Application: A representative Laravel application with authentication, Eloquent queries (3-5 per request), cache reads, and Blade template rendering. This simulates a real application, not a "Hello World" benchmark.

Tool: wrk with 100 concurrent connections, 30-second test duration.

Benchmark Results

Requests Per Second (Higher Is Better)

Configuration

RPS

Relative

PHP-FPM (10 workers)

850

1.0x (baseline)

Octane + FrankenPHP (4 workers)

2,100

2.5x

Octane + RoadRunner (4 workers)

2,350

2.8x

Octane + Swoole (4 workers)

2,600

3.1x

Octane provides a 2.5-3.1x improvement in requests per second depending on the driver. The improvement comes almost entirely from eliminating the framework boot overhead on each request.

Average Latency (Lower Is Better)

Configuration

P50

P95

P99

PHP-FPM

45ms

120ms

250ms

Octane + FrankenPHP

18ms

48ms

95ms

Octane + RoadRunner

16ms

42ms

88ms

Octane + Swoole

14ms

38ms

78ms

Latency improvements are consistent across percentiles. The P50 (median) improvement is roughly 2.5-3x, meaning your typical user sees noticeably faster responses.

Memory Usage

Configuration

Per-Worker Memory

Total (4 workers)

PHP-FPM

30-50MB

120-200MB

Octane + FrankenPHP

60-90MB

240-360MB

Octane + RoadRunner

55-85MB

220-340MB

Octane + Swoole

65-100MB

260-400MB

Octane workers use more memory per worker because they hold the entire bootstrapped application in memory. This is the trade-off: higher memory usage per worker in exchange for not having to bootstrap on every request.

However, you need fewer Octane workers to handle the same throughput. Four Octane workers at 2,500 RPS outperform ten PHP-FPM workers at 850 RPS, and the total memory usage is comparable.

Time to First Byte (TTFB)

Configuration

TTFB (cached page)

TTFB (DB query page)

PHP-FPM

25ms

48ms

Octane + FrankenPHP

5ms

20ms

Octane + RoadRunner

4ms

18ms

Octane + Swoole

3ms

16ms

TTFB improvement is the most dramatic metric. For cached pages, Octane's TTFB is 5-8x faster because the framework is already booted and the cached data is already in the worker's memory.

When PHP-FPM Is the Right Choice

Despite Octane's performance advantages, PHP-FPM remains the right choice for many applications:

Compatibility

PHP-FPM is compatible with every PHP library and Laravel package. No code auditing for static state, no worrying about request isolation, no special testing for memory leaks.

Simplicity

PHP-FPM requires no special configuration beyond worker count tuning. There are no memory leak risks, no state isolation concerns, and decades of troubleshooting knowledge available.

Low-Traffic Applications

If your application handles fewer than 500 requests per minute, the performance difference between PHP-FPM and Octane is imperceptible to users. A 45ms response versus a 15ms response is not meaningfully different in user experience when the majority of perceived latency comes from network round trips and frontend rendering.

Applications with Problematic Packages

Some packages store state in static properties or singleton bindings that are not properly flushed between requests. In an Octane environment, this can cause data from one request to leak into another. While the Laravel community has largely adapted to Octane, older or less-maintained packages may still cause issues.

When Octane Is the Right Choice

High-Traffic Applications

If your application handles thousands of requests per minute and you want to reduce the number of servers needed, Octane's 2.5-3x throughput improvement directly translates to infrastructure cost savings.

Latency-Sensitive Applications

APIs where response time is critical (real-time dashboards, financial applications, gaming backends) benefit significantly from Octane's reduced latency.

Cost Optimization

Three Octane web servers can often handle the load that would require eight PHP-FPM servers. At scale, this infrastructure reduction is substantial.

WebSocket Applications

If you are using Laravel Reverb for real-time features, Octane provides a natural fit — the persistent process model aligns well with long-lived WebSocket connections.

Deploying Octane on Deploynix

Deploynix supports all three Octane drivers. When configuring a site, you can select your preferred Octane driver, and Deploynix handles the server configuration:

  • FrankenPHP: Deploynix installs FrankenPHP and configures it as the application server, replacing the Nginx-to-PHP-FPM pipeline.
  • Swoole: Deploynix installs the Swoole extension and configures Nginx to reverse-proxy to the Swoole server.
  • RoadRunner: Deploynix installs the RoadRunner binary and configures Nginx to reverse-proxy to the RoadRunner server.

In all cases, Nginx remains in front as a reverse proxy, handling SSL termination, static file serving, and gzip compression. The Octane server handles only dynamic PHP requests.

Zero-Downtime Deployment with Octane

Deploynix handles zero-downtime deployments for Octane by:

  1. Deploying new code to the release directory
  2. Signaling the Octane server to reload workers
  3. New workers boot with the updated code
  4. Old workers finish their in-flight requests and shut down

This process is seamless and does not drop any requests.

Migration Checklist: PHP-FPM to Octane

If you decide to switch from PHP-FPM to Octane, follow this checklist:

  1. Audit static properties. Any class with static properties that store request-specific data will leak state between requests. Refactor to use request-scoped bindings or flush state in Octane's RequestHandled listener.
  2. Check singleton bindings. Service container singletons persist across requests in Octane. Ensure singletons do not accumulate request-specific state.
  3. Test file uploads. Temporary uploaded files may behave differently in Octane. Verify your upload handling works correctly.
  4. Monitor memory usage. Run your application under load and watch worker memory over time. If memory grows continuously, you have a leak that needs fixing. Octane can restart workers after a configurable number of requests as a safety net.
  5. Test thoroughly. Run your full test suite. Test every feature manually. Deploy to staging before production.
  6. Configure worker restart. Set --max-requests=500 (or similar) in your Octane configuration to periodically restart workers and reclaim any accumulated memory.

Conclusion

PHP-FPM and Laravel Octane serve different points on the simplicity-performance spectrum. PHP-FPM is the safe, proven choice that works with everything and requires minimal configuration. Octane delivers 2.5-3x higher throughput and significantly lower latency, at the cost of increased memory usage and the need to audit your application for state management issues.

For new applications on Deploynix, our recommendation is to start with PHP-FPM. It gives you a stable, predictable foundation while you build features and grow your user base. When your traffic justifies the switch — or when latency becomes a competitive advantage — migrate to Octane. The deployment process on Deploynix is the same either way, and switching between PHP-FPM and Octane is a configuration change, not an architectural overhaul.

Among the Octane drivers, FrankenPHP offers the best balance of performance and simplicity for most teams. Swoole provides the highest raw performance for teams willing to manage a PHP extension. RoadRunner sits in between, offering strong performance without requiring a PHP extension. All three are well-supported on Deploynix, so the choice comes down to your team's preferences and requirements.

The best application server is the one that meets your performance needs without introducing complexity you cannot maintain. For most Laravel applications, that starts with PHP-FPM and evolves to Octane when the numbers demand it.

Top comments (0)