Back to blog
Laravel
Intermediate

Laravel Octane: The Complete Guide to High-Performance PHP Applications

Laravel Octane transforms your application into a persistent process model, delivering up to 10x the requests per second of traditional PHP. This complete guide covers installation, Swoole versus RoadRunner, warmup strategies, and production deployment.

January 14, 2026

Introduction

Laravel Octane is the most significant performance evolution in the framework's recent history. It moves your application away from the classic request-per-process lifecycle that has defined PHP since 1998 and replaces it with a persistent application process model. The result is a dramatic reduction in request latency and a substantial increase in requests per second—typically anywhere from three to ten times the throughput of a standard PHP-FPM deployment.

If your Laravel application is growing, if page load times are becoming a competitive disadvantage, or if infrastructure costs are scaling faster than your revenue, Laravel Octane is the lever that solves all three. But it is not a simple install-and-forget solution. Octane introduces a fundamentally different execution model that requires understanding of process lifecycle, request isolation, and the specific pitfalls that arise when your application stays resident in memory for extended periods.

In this complete guide, you will learn exactly how Laravel Octane works under the hood, how to choose between Swoole and RoadRunner, how to configure and optimize your application for the persistent process model, and how to deploy it to production safely with zero downtime. We will cover real-world examples, production-grade code patterns, and the debugging techniques that separate teams who ship Octane from teams who roll it back.

Table of Contents

Core Concepts

Before you run a single command, you need to understand what Laravel Octane actually changes about how your application executes.

The Traditional PHP Lifecycle

In a conventional PHP deployment, every HTTP request follows the same sequence:

  1. The web server (Nginx) receives the request and passes it to PHP-FPM.
  2. PHP-FPM either spawns a new worker process or reuses an idle one.
  3. The public/index.php bootstrap file executes, loading Composer's autoloader, the service container, all service providers, and all registered global variables.
  4. Your application code runs, interacts with databases and caches, and produces a response.
  5. The process terminates immediately, releasing all memory.

The bootstrap steps 3 through 5 repeat on every single request. Even if your response takes ten milliseconds, you are paying the full cost of loading the framework, resolving thousands of services, parsing all your service providers, and initializing every singleton every time.

The Persistent Process Model

Laravel Octane changes this model fundamentally. When Octane starts your application, it boots Laravel once—executing all your service providers, resolving all services, building your entire dependency graph—and then keeps that process alive. Every subsequent request is handled by that same in-memory process.

This means your application bootstrap runs exactly once, not once per request. Your service container's singleton instances are shared across requests. Your compiled configuration cache, route cache, and config cache remain warm and never need to be rebuilt. The framework pays its bootstrapping cost a single time and reuses it thousands of times per second.

Request Isolation

If processes persist and state is shared, how does Octane prevent request A from leaking data into request B? This is the central challenge of any persistent process model, and Octane handles it through two complementary mechanisms.

First, Octane executes each request inside a sandboxed process or thread, depending on the driver you choose. The sandbox ensures that global PHP state—including global variables, static properties of your application classes, and request-scoped singletons—is reset between requests. Second, Octane provides the Octane::flushState() method and the Illuminate\Octane\Sandbox that guarantees request isolation by clearing global state and re-resolving request-bound services fresh for each request.

The critical implication for you as a developer: any state you store in global variables, static properties, or request-scoped singletons will persist across requests unless you explicitly clean it up. This is where most teams break Octane, and the following sections show you exactly how to avoid it.

Architecture Overview

Understanding the architecture helps you reason about failures and choose the right driver for your deployment.

The Swoole Driver

Swoole is a PHP extension written in C++ that provides an event-driven, high-performance networking engine. When you use the Swoole driver, Laravel Octane runs your application on Swoole's asynchronous runtime. Swoole handles HTTP requests directly, without a separate PHP-FPM worker layer.

Advantages of Swoole:

  • Native async I/O for database and queue operations, which can eliminate wait time on I/O-bound requests.
  • Very low overhead because there is no process-per-request fork cost.
  • Built-in features like Coroutines, WebSockets, and HTTP/2 that can extend your application beyond pure HTTP.

Disadvantages of Swoole:

  • The C++ extension must be compiled against your specific PHP version and operating system, which can create deployment friction.
  • The async model, while powerful, can surprise developers accustomed to synchronous code.
  • Debugging can be harder because the execution model differs from standard PHP.

The RoadRunner Driver

RoadRunner is a high-performance application server written in Go. It is a self-contained binary that runs as a separate process alongside PHP. PHP runs as a worker managed by RoadRunner, and RoadRunner handles the HTTP server, worker lifecycle, and request distribution.

Advantages of RoadRunner:

  • Simple binary installation with no PHP extension compilation required.
  • PHP runs in a conventional synchronous execution model, so your existing code mostly works unchanged.
  • Excellent production tooling, including built-in metrics, graceful shutdown, and easy process management.
  • Independent of your PHP version for the server component—you only compile PHP once.

Disadvantages of RoadRunner:

  • Does not provide native async I/O in the same way Swoole does, so I/O-bound requests still wait.
  • Additional process to manage and monitor in your deployment stack.

Which Should You Choose?

For most teams, RoadRunner is the recommended starting point. It offers the vast majority of Octane's performance benefit with far fewer operational complexities. You get a persistent PHP process, request isolation, zero-downtime deploys, and warm caches without needing to compile C++ extensions or reason about coroutines.

Choose Swoole when you have a team experienced with asynchronous PHP, when you need native WebSockets or coroutines, or when you are pushing for absolute maximum throughput and have the operational maturity to manage it. Many teams eventually adopt Swoole for the hot path of their application after proving the concept with RoadRunner.

Step-by-Step Guide

Follow these steps to install and configure Laravel Octane. This guide uses RoadRunner as the default driver.

Step 1: Create a New Laravel Project or Prepare Existing One

If you are starting fresh:

composer create-project laravel/laravel octane-appcd octane-app

For an existing application, ensure you are on Laravel 9 or later, as Octane requires recent Laravel versions.

Step 2: Install the Octane Package

Install Octane via Composer. This adds the framework-side integration and the octane artisan command.

composer require laravel/octanephp artisan octane:install

The octane:install command performs several useful setup tasks:

  • It publishes the config/octane.php configuration file.
  • It sets up your application's public directory to handle Octane routing.
  • It creates the Octane environment file and updates your environment configuration.

Step 3: Choose and Install Your Driver

RoadRunner installation is straightforward. On Linux with Docker available, you can use:

sudo curl -L https://github.com/roadrunner-server/roadrunner/releases/latest/download/roadrunner-linux-amd64.tar.gz | sudo tar xzf - -C /usr/local/bin

For Swoole, you need the extension compiled for your PHP version. On many Linux distributions, a PECL install works:

pecl install swoole

Verify the extension loads with php -m | grep swoole.

Step 4: Configure the Driver

Edit config/octane.php and set the driver to either swoole or roadrunner. The configuration file lets you control the number of application workers, the number of application threads per worker (for Swoole), and worker recycling settings.

return [    'driver' => env('OCTANE_DRIVER', 'roadrunner'),    'timeout' => 30,    'requests_per_tick' => 0,    'static_directory' => 'public',    'tick_max_seconds' => 0,    'garbage_collection_seconds' => 3600,    'opcache_file_stat_cache' => env('OCTANE_OPCACHE_FILE_STAT_CACHE', true),    'max_worker_memory' => 64,    'bootstrap' => base_path('bootstrap/octane.php'),];

Step 5: Generate the RoadRunner Configuration

RoadRunner needs its own configuration file, which Octane can generate for you:

php artisan octane:config

This creates a rr.yaml file tuned for your application's public directory and routes. In production, you will typically copy this file to a location your process manager can reference.

Step 6: Start Octane

Start the application with the artisan command:

php artisan octane:start

You will see output showing the worker count, the listening address, and confirmation that your application is serving requests. Keep this process running while you test.

Step 7: Run Your Application

Open your application in a browser or use a load testing tool like hey or wrk. Compare throughput against your pre-Octane baseline. You should see a noticeable reduction in average latency and a substantial increase in requests per second.

Real-World Examples

Let's walk through concrete scenarios where Octane changes the outcome.

Example 1: An API Endpoint Serving Complex Query Results

Imagine an endpoint that resolves a resource through the container, eager-loads twenty relationships, and returns JSON. In a traditional PHP-FPM deployment, every request loads the entire service container, parses all service providers, and re-resolves the database connections. With Octane, the container is built once, all eager-loaded relationships stay warm in memory through the request, and subsequent requests hit an already-resolved object graph.

Example 2: A Dashboard with Heavy Cache Dependency

A dashboard that reads thousands of cache keys per page load benefits directly from Octane because the cache client connection remains open and the configuration cache is never invalidated between requests. The framework never rebuilds the compiled class and config caches, so every request skips that overhead entirely.

Example 3: A Multi-Step Checkout Flow

For a checkout flow that maintains state across several requests, Octane preserves warm caches and open connections throughout the session (remembering that request-scoped data must not be stored in singletons). The cumulative latency savings across a six-step checkout can be the difference between a smooth purchase and cart abandonment.

Production Code Examples

Here are production-grade patterns for working safely and effectively with Laravel Octane.

Example 1: Explicitly Resetting Request State with Octane::event

Octane runs your event dispatchers in a way that guarantees events are handled within the current request context. No special code is required for most event listeners, but be aware that any static property you modify inside an event listener will persist across requests unless you clear it.

Example 2: Handling Octane-Ready Database Connections

By default, Octane keeps database connections open across requests for performance. This is usually desirable, but you must ensure your connection is truly connection-pool friendly. Laravel's Eloquent handles this well, but custom PDO wrappers may need explicit reset logic.

Example 3: Using Octane::task for Periodic Background Work

Octane provides Octane::task(), which allows you to schedule a callable to run at a fixed interval while your application is running. This is useful for maintenance tasks that should execute on a timer without relying on the system cron:

use Illuminate\Support\Facades\Octane;Octane::task(function () {    // Runs every 30 seconds while Octane is serving requests    Cache::tags(['api'])->flush();}, 30);

Example 4: Gracefully Cleaning Up Global State

If you must store request-scoped data globally, reset it in a service provider's boot method or use the Illuminate\Octane\Events\Tick event for periodic cleanup. Never rely on the destructor or on PHP's garbage collector to clear your application state between requests.

class AppServiceProvider extends ServiceProvider{    public function boot(): void    {        if (class_exists('Illuminate\Octane\Events\Tick')) {            Octane::listen(function () {                // Clear known request-scoped singletons here            });        }    }}

Comparison Table

This comparison breaks down the primary options you will face when adopting Octane.

AspectPHP-FPM (Traditional)Octane + RoadRunnerOctane + Swoole
Application bootstrapOnce per requestOnce per worker lifetimeOnce per worker lifetime
Memory per workerForked per request, released afterPersistent, configured recyclePersistent, configured recycle
Throughput gainBaseline3x to 10x4x to 12x
Installation complexityLowLow (Go binary)Medium (C extension compile)
Async I/O supportNoneLimitedFull native support
Debugging difficultyStandard XdebugStandard Xdebug, process awareHarder, coroutine context
Recommended for most teamsYes (before Octane)YesAdvanced teams only

Best Practices

  1. Always clear request-scoped state. Do not store user IDs, session data, or cached objects in static properties or global variables.
  2. Keep worker memory in check. Set max_worker_memory and enable worker recycling so workers restart periodically and release leaked memory.
  3. Test under load before production. Use wrk, hey, or k6 to establish a baseline and verify your Octane deployment handles expected concurrency.
  4. Monitor worker health. RoadRunner exposes metrics; watch for worker crashes, recycling events, and memory growth trends.
  5. Do not rely on __destruct for cleanup. Persistent processes may not destroy objects the way you expect between requests.
  6. Use dedicated Octane environments. Keep your Octane process separate from queued worker processes so a stuck Octane request cannot starve your queue workers.
  7. Cache aggressively but invalidate deliberately. Warm caches are a primary Octane benefit, but invalidation logic must be request-safe.
  8. Keep Xdebug off in production. Xdebug adds significant per-request overhead that defeats Octane's purpose. Use it only in development for debugging Octane-specific issues.

Common Mistakes

These are the mistakes that cause Octane deployments to fail or behave unpredictably.

Mistake 1: Storing State in Singletons

Using a singleton to cache the current user, a request-specific service, or a database query result means that data persists across requests. Request A's user can appear as Request B's user. Always resolve fresh request data from the container rather than caching it in a singleton.

Mistake 2: Assuming $GLOBALS and Static Properties Are Clean

Global PHP variables and static class properties are the classic persistent-state vectors. Octane's sandbox clears many of these, but not all of them reliably. Audit your code for static caches and global assignments and remove or reset them.

Mistake 3: Relying on Cron for Time-Sensitive Jobs

In a persistent process, you may not need cron at all for periodic work. But if you do use cron alongside Octane, ensure cron jobs do not assume a freshly booted process and that they handle the case where their target worker is busy.

Mistake 4: Not Configuring Worker Recycling

Without worker recycling, memory leaks accumulate until a worker crashes or consumes excessive RAM. Set opcache_file_stat_cache, configure garbage_collection_seconds, and monitor max_worker_memory.

Mistake 5: Ignoring Queue Worker Conflicts

Octane does not manage your queued jobs by default. Running php artisan queue:work alongside Octane can lead to worker starvation when an Octane request holds resources. Consider separate worker pools or use Octane's built-in capabilities where appropriate.

Performance Tips

  1. Enable all framework caches. Make sure config:cache, route:cache, and view:cache are enabled in production. With Octane, the framework bootstraps once and these caches are loaded once for the worker's entire lifetime.
  2. Minimize service provider work. Even though providers only boot once per worker, heavy provider logic still adds to initial startup time and increases the memory footprint of every worker.
  3. Use Redis for session and cache drivers. Redis is fast, connection-pool friendly, and plays nicely with persistent processes. Avoid file-based sessions under Octane.
  4. Enable OPcache. OPcache must be enabled for Octane to realize its full potential. With OPcache off, Octane provides little benefit.
  5. Reduce external HTTP calls. Persistent processes make external API calls more noticeable because the connection setup happens once per request. Consider connection pooling or batching where possible.
  6. Profile before optimizing. Use RoadRunner's built-in profiling or Xdebug in development to identify where time is actually spent before micro-optimizing.
  7. Consider Swoole coroutines for I/O-bound bottlenecks. Once you have RoadRunner working and still need more throughput on I/O-heavy endpoints, evaluate migrating those endpoints to Swoole's coroutine model.

Security Considerations

Persistent processes change the threat model in subtle ways.

Request Isolation Is Your Responsibility

Octane provides request isolation mechanisms, but the framework cannot audit your entire codebase. Any static property or global variable that retains request data becomes a cross-request data leak vector. Before enabling Octane, audit your application for persistent state, especially in middleware, service providers, and event listeners.

Memory Safety of the Underlying Runtime

With Swoole, the C extension is a third-party codebase running with the same privileges as your application. Keep Swoole updated to the latest stable version and patch promptly for any disclosed vulnerabilities. RoadRunner, being Go-written, has a smaller attack surface but still requires updates.

Do Not Log Sensitive Data to Shared Files

A persistent process may write to shared log files across multiple requests. Ensure log rotation is configured and that sensitive data such as tokens, passwords, or personally identifiable information is never written to logs. Consider structured logging with per-request correlation IDs.

Validate and Sanitize Regardless of Runtime

Octane does not provide additional security guarantees for input validation. Continue to validate all user input, authorize every action, and use parameterized queries. The runtime change does not relax any security model.

Secure the Management Interface

RoadRunner exposes a management interface and metrics endpoint. Protect these with proper authentication, firewall rules, or isolation so they are not publicly accessible.

Deployment Notes

Deploying Octane requires attention to process management and graceful shutdown.

Process Management

You need a process manager to keep your Octane worker running. Supervisor is the most common choice on Linux:

[program:octane]command=php /var/www/html/artisan octane:start --host=127.0.0.1 --port=8000directory=/var/www/htmlautostart=trueautorestart=truestopasgroup=truekillasgroup=trueuser=www-datanumprocs=1redirect_stderr=truestdout_logfile=/var/log/octane/octane.log

For RoadRunner specifically, you may manage the RoadRunner binary and the Octane process separately. RoadRunner itself can be launched with rr serve and configured to manage PHP workers.

Zero-Downtime Deployments

Octane enables zero-downtime deployments because worker restarts do not kill in-flight requests the way a PHP-FPM master restart would. The deployment workflow is:

  1. Stop traffic or drain connections from the load balancer.
  2. Start a new Octane process with the updated code.
  3. Verify the new process is healthy and serving requests.
  4. Gracefully stop the old process.
  5. Resume traffic.

RoadRunner supports graceful shutdown signals, so a properly configured deployment can drain existing requests before terminating a worker.

Nginx Configuration

Point your Nginx server block at the Octane host and port. You must also serve static assets correctly, which Octane configures automatically through the static_directory setting. Ensure your location blocks for static files pass through without proxying to the Octane process.

server {    listen 80;    server_name example.com;    location / {        proxy_pass http://127.0.0.1:8000;        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection 'upgrade';        proxy_set_header Host $host;        proxy_cache_bypass $http_upgrade;    }    location /public {        alias /var/www/html/public;        expires 1y;        add_header Cache-Control "public, immutable";    }}

Debugging Tips

  • Enable OCTANE_DEBUG in development. Setting this environment variable gives you additional logging about worker lifecycle events, state resets, and task scheduling.
  • Watch the worker count and health. If workers are restarting unexpectedly, check logs for out-of-memory kills or exceptions. RoadRunner logs worker crashes explicitly.
  • Use request IDs. Add a unique request identifier to every response header so you can trace a specific request through logs, especially when a worker handles many requests.
  • Test with a clean environment. If you suspect stale state is causing a bug, restart the Octane worker and retest. Persistent state issues often only appear intermittently.
  • Check memory usage per worker. Use ps, top, or RoadRunner's metrics to verify workers are not growing unboundedly. Sudden growth indicates a leak that worker recycling must mitigate.
  • Disable OPcache during debugging. Sometimes OPcache caching of changed files during development creates confusion. Set opcache.validate_timestamps to 1 in development and 0 in production.

FAQ

1. Does Laravel Octane work with all Laravel features?

Octane works with the vast majority of Laravel features. However, features that rely on a fresh process per request—such as certain static caches, global state, or code that assumes __destruct fires—may misbehave. Every aspect of your application should be tested under Octane.

2. Do I need to rewrite my application to use Octane?

No. Octane is additive. Your existing routes, controllers, models, and services continue to work without modification. You only need to add request-safe code patterns where persistent state is a risk.

3. Will Octane make my application slower during boot?

Boot time increases slightly because the application is fully initialized once per worker. But because boot happens once per worker rather than once per request, average request latency decreases dramatically. First-request latency is the only noticeable cost.

4. Can I use Octane with PHP's JIT?

Yes, but JIT provides limited benefit for a request-bound workload that spends most of its time in I/O or waiting on external services. Measure before relying on JIT as a performance lever.

5. Is Octane compatible with PHP 8.1 and 8.2?

Octane supports recent PHP versions. Always check the official Laravel Octane documentation for the specific PHP versions your Laravel version supports, and keep your PHP runtime patched.

6. How do I handle file uploads with Octane?

File uploads work the same as in traditional deployments because the request object is still fully available. Just be mindful that uploaded file temporary state does not persist in your application's own state.

7. Can Octane run WebSockets?

Yes, but only with the Swoole driver, which provides native WebSocket support. The RoadRunner driver does not include built-in WebSocket handling, so you would need a separate process for WebSocket connections.

8. How do I monitor Octane in production?

RoadRunner exposes Prometheus metrics and an admin endpoint. Laravel Octane also logs worker lifecycle events to your standard logging channel. Combine these with your existing monitoring stack and set alerts for worker restarts, memory thresholds, and request latency.

9. What happens if a request crashes a worker?

The offending worker is terminated and a new worker is spawned to replace it. This is why worker recycling is essential—it guarantees that a crash does not leave your application with a broken process. Configure appropriate garbage_collection_seconds and max_worker_memory limits.

10. Is Octane worth it for small applications?

For small applications with low traffic, the operational complexity of Octane may not justify the benefit. Octane pays off most when your application is traffic-bound, has high per-request latency, or is constrained by infrastructure cost. Start with performance profiling before adopting it.

Conclusion

Laravel Octane is a proven, production-ready way to extract three to ten times the throughput from your Laravel application without rewriting any of your business logic. It shifts the framework's bottleneck from process bootstrapping to your actual application code, which is where you want it to be.

Start with RoadRunner. Validate the performance gains against your own baseline. Audit your code for persistent-state vulnerabilities. And only move to Swoole when you have a measured need for native async I/O and the operational maturity to support it.

Ready to put Laravel Octane to work? Download the official Octane documentation, clone a test repository, and run your first php artisan octane:install today. If you found this guide useful, check out our Laravel Horizon guide for queue worker management and our Laravel performance optimization article for a broader view of application tuning. Have questions about your specific Octane deployment? Join the discussion and share your baseline numbers.