Laravel Octane: Supercharge Your App with High-Performance Serving
Master Laravel Octane to boost performance using Swoole or RoadRunner.
20+ years shipping production PHP systems at scale. Everything here is grounded in real deployments.
- ✓Basic knowledge of Laravel framework
- ✓Familiarity with Composer and PHP CLI
- ✓Access to a server with root privileges (for Swoole installation)
- ✓Understanding of HTTP and request lifecycle
- Laravel Octane supercharges your application by keeping it in memory across requests, eliminating bootstrap overhead.
- It supports Swoole and RoadRunner as high-performance application servers.
- Octane can increase throughput by 10-30x compared to traditional PHP-FPM.
- Requires careful handling of static properties, singletons, and request-specific state.
- Production deployment needs proper configuration, monitoring, and graceful shutdown.
Imagine a restaurant kitchen. Traditional PHP-FPM is like a chef who prepares every dish from scratch, including washing the pans and chopping vegetables, for each customer. Laravel Octane is like a chef who keeps the kitchen prepped and ready, so when an order comes in, they just cook the dish quickly. This makes serving many customers much faster.
Laravel Octane is a first-party package that dramatically boosts your Laravel application's performance by using high-powered application servers like Swoole and RoadRunner. Instead of booting the framework from scratch for every request (as with PHP-FPM), Octane boots the application once, keeps it in memory, and reuses it across all subsequent requests. This eliminates the overhead of framework bootstrap, configuration loading, and service container resolution, resulting in massive performance gains—often 10 to 30 times more requests per second.
But with great power comes great responsibility. Octane's long-lived application state introduces new challenges: you must be careful with static properties, singletons, and any mutable global state. A memory leak or stale data can affect subsequent requests. This tutorial will guide you through setting up Octane, writing Octane-safe code, deploying to production, and debugging common issues. You'll learn how to harness Octane's power without falling into its traps.
Whether you're building a high-traffic API, a real-time dashboard, or a SaaS platform, Octane can help you serve more users with fewer servers. Let's dive in and supercharge your Laravel app.
Installation and Configuration
To get started with Laravel Octane, you need to install the package via Composer. Octane requires either Swoole or RoadRunner as the underlying server. For this tutorial, we'll use Swoole, which is a PHP extension that provides an event-driven, asynchronous, concurrent networking framework.
First, install the Octane package:
``bash composer require laravel/octane ``
Next, install Swoole via PECL or using the official Docker image. For local development, you can use the provided Docker setup. After installation, publish the Octane configuration:
``bash php artisan octane:install ``
This will create a config/octane.php file where you can configure the server, worker count, max requests per worker, and more. A typical configuration might look like:
``php return [ 'server' => env('OCTANE_SERVER', 'swoole'), 'workers' => env('OCTANE_WORKERS', 4), 'max_requests' => 500, 'swoole' => [ 'options' => [ 'log_file' => storage_path('logs/swoole.log'), 'log_level' => 4, ], ], ]; ``
Now you can start Octane:
``bash php artisan octane:start ``
By default, Octane listens on port 8000. You can test it by visiting http://localhost:8000. For production, you'll want to use a process monitor like Supervisor to keep Octane running.
max_requests to a value like 500 to prevent memory leaks from accumulating. This forces workers to restart after serving that many requests.Writing Octane-Safe Code
Octane's long-lived application state means you must be careful with global or static state. Any mutable static property or singleton that holds request-specific data will persist across requests, causing data leakage and bugs.
Avoid static properties that change per request. For example:
```php class UserService { public static $user;
public function setUser($user) { self::$user = $user; } } ```
This is dangerous because $user will be overwritten by concurrent requests. Instead, use request-scoped dependencies or pass data via method parameters.
Use scoped bindings in the service container. Instead of registering a singleton, use a closure that returns a new instance per request:
``php $this->app->bind(UserService::class, function ($app) { return new UserService($app['request']->user()); }); ``
Leverage Octane's flush strategies for caches that should be cleared per request. Octane provides a flush method on the Octane facade that you can call in middleware to reset state:
```php use Laravel\Octane\Facades\Octane;
public function handle($request, $next) { $response = $next($request); Octane::flush(); return $response; } ```
This will reset any registered flushable instances. You can also use the Octane::flush() method in your code after sending a response.
Be cautious with facades that cache data. For example, Config::get() caches configuration values, but that's fine because config is immutable. However, facades like Cache that store data in memory may need careful handling.
Octane::flush() after each request to ensure clean state. But be mindful of performance; only flush what's necessary.Handling Database Connections and Queues
Octane works with Laravel's database and queue systems, but you need to be aware of connection pooling and transaction management.
Database connections are reused across requests. Octane automatically manages connection pooling for MySQL and PostgreSQL. However, if you use transactions, ensure they are committed or rolled back before the request ends. A dangling transaction can block subsequent queries.
Queue workers can be run alongside Octane. However, Octane's workers are not queue workers. You should run separate queue workers using php artisan queue:work. Octane can also dispatch jobs synchronously, but for heavy jobs, use a dedicated queue.
Redis connections are also pooled. Be careful with Redis transactions and pub/sub. Avoid blocking operations like BLPOP in request handlers; use async alternatives.
Example of safe transaction handling:
``php DB::beginTransaction(); try { // ... DB::commit(); } catch (\Exception $e) { DB::rollBack(); throw $e; } ``
Always ensure transactions are closed. In Octane, if an exception occurs and the transaction is not rolled back, the connection will be returned to the pool with an open transaction, causing issues for the next request.
'options' => [PDO::ATTR_EMULATE_PREPARES => true] in your database config to reduce memory usage in Octane.Deploying Octane to Production
Deploying Octane requires a process manager like Supervisor to keep the server running. Here's a sample Supervisor configuration:
``ini [program:laravel-octane] process_name=%(program_name)s_%(process_num)02d command=php /path/to/artisan octane:start --server=swoole --host=0.0.0.0 --port=8000 autostart=true autorestart=true user=forge numprocs=1 redirect_stderr=true stdout_logfile=/path/to/storage/logs/octane.log stopwaitsecs=60 ``
Graceful shutdown is important. Octane listens for signals like SIGTERM and will finish current requests before shutting down. Ensure your Supervisor config sends the correct signal.
Health checks should verify that Octane is responding. You can create a simple route:
``php Route::get('/health', function () { return ``response()->json(['status' => 'ok']); });
Then configure your load balancer to hit this endpoint.
Environment variables like APP_ENV and APP_DEBUG should be set appropriately. In production, set APP_DEBUG=false and OCTANE_WORKERS to the number of CPU cores.
Logging is crucial. Octane logs to the file specified in config. Monitor these logs for errors and warnings.
OCTANE_MAX_REQUESTS to a value like 500 to automatically recycle workers and prevent memory leaks.Monitoring and Debugging Octane
Monitoring Octane in production is essential. Key metrics to watch:
- Memory usage: Use
php artisan octane:statusto see memory per worker. Set up alerts if memory exceeds a threshold. - Request throughput: Use tools like Laravel Telescope or New Relic.
- Worker restarts: If workers restart frequently, check for exceptions or memory limits.
Debugging tips:
- Use
php artisan octane:reloadto gracefully restart workers without downtime. - Enable Swoole's
tracelog level for detailed debugging. - Use
ordd()carefully; they may output to the console of the worker, not the HTTP response. Usedump()instead.logger() - For profiling, use Blackfire or Xdebug with caution. Xdebug can slow down Octane significantly.
Common issues:
- Stale data: If you see data from previous requests, check for static caches or singletons.
- Connection timeouts: Increase
max_execution_timein Swoole options. - Serialization errors: When using queues, ensure job payloads are serializable. Avoid closures that capture request objects.
octane:reload for graceful restarts, and avoid debugging functions that kill workers.Advanced: Coroutines and Async I/O
Swoole provides coroutines that allow concurrent I/O operations without blocking the worker. This can further boost performance for I/O-bound tasks like multiple database queries or HTTP calls.
Using coroutines in Octane:
```php use Swoole\Coroutine; use Illuminate\Support\Facades\Http;
$responses = Coroutine::wait([ Coroutine::create(function () { return Http::get('https://api.example.com/users'); }), Coroutine::create(function () { return Http::get('https://api.example.com/posts'); }), ]); ```
However, be cautious: Laravel's facades and Eloquent are not coroutine-safe. You must ensure that any shared state is not mutated concurrently. Use and go() carefully.defer()
Octane's task workers can be used for CPU-intensive tasks. Configure them in config/octane.php:
``php 'swoole' => [ 'options' => [ 'task_worker_num' => 4, ], ], ``
Then dispatch tasks:
``php $result = Octane::task(function () { // CPU-intensive work return heavyComputation(); }); ``
Task workers run in separate processes, so they don't block request handling.
The Case of the Leaking Singleton: A Production Outage
bind with a closure that returns a new instance per request) or ensured the singleton did not hold request-specific data. Also added memory limit monitoring and alerts.- Never store request-specific data in singletons or static properties.
- Use scoped bindings for services that depend on request state.
- Monitor memory usage closely when deploying Octane.
- Test under load with realistic traffic patterns before production.
- Implement graceful shutdown and health checks to detect leaks early.
php artisan octane:reloadphp artisan octane:status| File | Command / Code | Purpose |
|---|---|---|
| config | return [ | Installation and Configuration |
| app | namespace App\Http\Middleware; | Writing Octane-Safe Code |
| app | namespace App\Http\Controllers; | Handling Database Connections and Queues |
| [program:laravel-octane] | Deploying Octane to Production | |
| app | namespace App\Console\Commands; | Monitoring and Debugging Octane |
| app | namespace App\Http\Controllers; | Advanced |
Key takeaways
Common mistakes to avoid
3 patternsUsing static properties to store request data
Not closing database transactions
Using dd() or dump() in request handlers
Interview Questions on This Topic
What is Laravel Octane and how does it improve performance?
Frequently Asked Questions
20+ years shipping production PHP systems at scale. Everything here is grounded in real deployments.
That's Laravel. Mark it forged?
4 min read · try the examples if you haven't