Still Using PHP-FPM? Here's How We Cut Laravel API Response Times by 60%

Copy link

A 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

MetricBefore (PHP-FPM)After (Octane + FrankenPHP)Improvement
Average Response Time60ms24ms60% faster
P95 Response Time200ms54ms73% faster
Requests/Second~165 req/s~410 req/s148% increase
Memory Efficiency50 workers × 50MB32 workers × 100MBBetter 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.

Avatar

Erit Islami

Head of Product Dev

Sep 03, 2025