Still Using PHP-FPM? Here's How We Cut Laravel API Response Times by 60%
Copy linkA practical guide to ditching PHP-FPM and achieving significant performance gains
When our Laravel APIs started feeling sluggish under increased load, we knew it was time to modernize our stack. What we discovered was a game-changer: by migrating from traditional PHP-FPM to Laravel Octane + FrankenPHP, we achieved a 60% reduction in average response times (60ms → 24ms) and a 73% improvement in P95 latency (200ms → 54ms).
The PHP-FPM Bottleneck
Traditional Laravel deployments rely on PHP-FPM (FastCGI Process Manager), which has served us well for years. However, PHP-FPM has inherent limitations that become apparent under modern workloads:
The Bootstrap Problem: Every request requires PHP-FPM to:
- Spawn or reuse a worker process
- Bootstrap the entire Laravel application
- Load configuration, service providers, and dependencies
- Execute the request
- Tear down the request context
On our 16 vCPU server, we were limited to roughly 100 concurrent PHP-FPM workers, leaving CPU cores underutilized while requests queued up waiting for available workers.
Memory Inefficiency: Each PHP-FPM worker maintains its own memory space, leading to duplicated application code and configuration across processes.
Enter Laravel Octane + FrankenPHP
Laravel Octane fundamentally changes how Laravel applications handle requests by keeping the application bootstrapped in memory between requests. Instead of the traditional request-response cycle, Octane workers stay alive and handle multiple requests sequentially.
FrankenPHP is a modern PHP application server written in Go that:
- Provides native HTTP/2 and HTTP/3 support
- Uses lightweight goroutines instead of heavy processes
- Eliminates the need for a separate web server like nginx for PHP processing
- Integrates seamlessly with Laravel Octane
The key advantage: Your Laravel application boots once and stays in memory, dramatically reducing the overhead of each request.
Implementation: From Theory to Production
Step 1: Server Preparation
We started with a 16 vCPU, 32GB RAM server on Hetzner Cloud. The first step was optimizing our PHP configuration for long-running processes.
PHP CLI Configuration Updates:
memory_limit = 1024M
max_execution_time = 60
opcache.enable_cli = 1
opcache.memory_consumption = 512M
opcache.jit = 1255
opcache.jit_buffer_size = 128M
realpath_cache_size = 4096K
realpath_cache_ttl = 600
Key insight: Since Octane runs as CLI processes, your PHP CLI configuration becomes critical, not just PHP-FPM settings.
Step 2: Installing Octane with FrankenPHP
# Install Octane
composer require laravel/octane
# Install FrankenPHP server
php artisan octane:install --server=frankenphp
We modified our optimized nginx configuration to proxy requests to FrankenPHP
location / {
try_files $uri $uri/ @octane;
}
location @octane {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Additional proxy headers...
}
This hybrid approach lets nginx handle static assets while FrankenPHP processes PHP requests.
Step 3: Configuration Optimization
Octane Worker Configuration:
OCTANE_WORKERS=32 # 2x CPU cores
OCTANE_TASK_WORKERS=16 # Background task processing
OCTANE_MAX_REQUESTS=1000 # Worker recycling to prevent memory leaks
Step 4: Deployment Integration
We updated our deployment script to properly manage Octane workers:
php artisan octane:reload # Gracefully restart workers
We manage the Octane process as a daemon, ensuring it restarts automatically and integrates with the deployment pipeline.
The Results: Numbers Don't Lie
After implementing these changes, we observed the performance via Nightwatch
Metric | Before (PHP-FPM) | After (Octane + FrankenPHP) | Improvement |
---|---|---|---|
Average Response Time | 60ms | 24ms | 60% faster |
P95 Response Time | 200ms | 54ms | 73% faster |
Requests/Second | ~165 req/s | ~410 req/s | 148% increase |
Memory Efficiency | 50 workers × 50MB | 32 workers × 100MB | Better utilization |
Key Lessons Learned
1. Resource Allocation Matters
With 32 Octane workers, we achieved better CPU utilization across all 16 cores compared to the PHP-FPM workers we were running previously.
2. Memory vs. Performance Trade-off
While individual Octane workers use more memory (100MB vs 50MB for PHP-FPM), the overall system efficiency improved dramatically due to eliminated bootstrap overhead.
3. Database Connections Need Attention
With more concurrent workers, we had to optimize MySQL connection limits and buffer pool settings to handle the increased concurrent load.
4. Monitoring is Critical
Long-running processes require different monitoring approaches. We now track worker memory usage and restart frequency to catch potential memory leaks early.
Considerations and Gotchas
Memory Leaks: Long-running processes can accumulate memory leaks. The OCTANE_MAX_REQUESTS
setting helps by recycling workers periodically.
Shared State: Be cautious of global state and static variables that might persist between requests. Octane provides guidelines for avoiding common pitfalls.
Third-party Packages: Some packages aren't designed for long-running processes. Test thoroughly and check package compatibility.
Is This Right for Your Application?
Octane + FrankenPHP is particularly beneficial if you:
- Handle moderate to high request volumes
- Have sufficient server resources (4GB+ RAM recommended)
- Can dedicate time to proper testing and monitoring
- Want to modernize without architectural changes
For smaller applications with minimal traffic, the traditional PHP-FPM setup might be perfectly adequate and simpler to manage.
Looking Forward
This optimization gave us significant headroom for growth without requiring additional infrastructure investment. The improved response times directly enhanced user experience, and the better resource utilization means we can handle traffic spikes more gracefully.
Our next steps include exploring HTTP/3 support and investigating Laravel's upcoming performance features that work particularly well with Octane.
Resources
The performance improvements outlined in this article were measured on a 16 vCPU, 32GB RAM server running Laravel 11.x with MySQL 8.0. Your results may vary based on application complexity, traffic patterns, and infrastructure configuration.

Erit Islami
Head of Product Dev
Sep 03, 2025