TL;DR — Laravel Octane runs your application on a long-running server (Swoole or RoadRunner). By keeping the framework in memory between requests, it eliminates bootstrap overhead, significantly lowering latency and increasing throughput.
What is Laravel Octane exactly ?
In the classic PHP-FPM model, every request boots the entire Laravel framework from scratch. Octane changes this paradigm:
- A master process manages a pool of workers.
- The framework is booted once and stays "warm" in memory.
- Each incoming request is handed to an already-booted worker.
- The worker returns the response and stays alive for the next hit
In practice:
- A master process manages N workers.
- Each request is handed to an already‑booted worker.
- Response returns; the worker stays alive for the next request.
This approach dramatically improves p95/p99 latency, making your application feel incredibly snappy under load.
When to Use Octane (and When to Skip)
Octane is powerful, but it's not a "magic button" for every project.
- A magic button for bad code. Unindexed queries and N+1s will still hurt.
- A replacement for queues. Keep heavy work in jobs (Horizon/Redis).
- A free pass to global state. Workers persist, so be mindful of mutable singletons/statics.
When Octane shines (and when to skip)
Use it if…
- You have steady or spiky traffic, APIs or pages hit frequently.
- The app is mostly I/O‑bound (DB, HTTP calls, storage).
- You want lower latency without scaling up PHP‑FPM aggressively.
Probably skip if…
- Simple brochure site, low traffic.
- Heavy CPU‑bound work in the request cycle (move it to queues first).
- Codebase relies on global/mutable state that’s hard to untangle.
Under the hood (request lifecycle)
[Client] → [Reverse proxy] → [Octane master] → [Warm worker handles request] → [Response]
↑ (Laravel already booted)
workers
Octane also provides niceties like hot reloads, request‑scoped containers, and an in‑memory cache driver (for single instance use‑cases).
Quick start (local)
composer require laravel/octane
php artisan octane:install
Pick your server:
Swoole (extension):
# install the extension (Swoole or OpenSwoole)
pecl install swoole
# then run
php artisan octane:start --server=swoole
RoadRunner (binary):
# download the rr binary via composer plugin
./vendor/bin/rr get
# then run
php artisan octane:start --server=roadrunner
Stateless discipline (important)
Because workers live long, per‑request data must not leak:
- Avoid mutable singletons/statics holding request/user data.
- Prefer request‑scoped bindings or pass data explicitly.
- Reset per‑request caches in middleware when appropriate.
- Store sessions/cache in shared backends (Redis/DB) if you run multiple workers/instances.
Tip: schedule worker recycling (max requests) to mitigate memory growth; keep an eye on RSS/CPU.
Sessions, cache, files
- Use a shared session driver (
redis,database) for multi‑worker/multi‑instance setups. - Cache: a central store (Redis) is safer across nodes; Octane’s in‑memory cache is per‑process only.
- Files: serve from a shared disk/S3 when horizontally scaling.
Queues still matter
Octane cuts request overhead; queues cut work from the request. Keep emails, image/PDF processing, and webhooks in jobs (Horizon is great for metrics/retries). The fastest response is the one that does less.
Observability
Measure before/after. Track:
- Total/slow requests, p95/p99
- DB time and query count (Debugbar/Telescope)
- Worker memory, restarts, and error rates
- Reverse proxy and OS metrics (CPU, load, I/O)
Reverse proxy (Nginx) — minimal example
server {
listen 80;
server_name example.com;
client_max_body_size 16m;
location / {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 60s;
proxy_connect_timeout 5s;
proxy_pass http://127.0.0.1:8000;
}
}
Start Octane to listen on 127.0.0.1:8000 and keep Nginx as the public entrypoint.
Process manager (systemd) — example
# /etc/systemd/system/octane.service
[Unit]
Description=Laravel Octane (Swoole or RoadRunner)
After=network.target
[Service]
User=www-data
WorkingDirectory=/var/www/app
Environment=APP_ENV=production
ExecStart=/usr/bin/php artisan octane:start --server=swoole --host=127.0.0.1 --port=8000
ExecStop=/usr/bin/php artisan octane:stop
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Reload systemd and enable:
sudo systemctl daemon-reload
sudo systemctl enable --now octane
Swap --server=roadrunner if you prefer RR (ensure the rr binary is available).
Pre‑flight checklist (copy/paste)
- [ ] N+1 fixed, heavy queries indexed, reasonable caching in place
- [ ] Sessions & cache on a shared backend (Redis/DB)
- [ ] No request data stored in globals/singletons
- [ ] Worker recycling configured (max requests) and monitored
- [ ] Reverse proxy + process manager configured
- [ ] Before/after metrics ready (p95/p99, DB time, memory)
Troubleshooting notes
- Works in dev, fails in prod → missing Swoole/rr binary, wrong user/paths in service file.
- Memory creeping up → long‑lived state or large caches kept in memory; audit singletons and enable worker recycling.
- Sticky sessions → don’t rely on local session files when scaling horizontally; move to Redis/DB.
- No latency gain → the app is CPU‑bound or DB‑bound; profile and offload/optimize first.
Wrap‑up
Octane removes the per‑request overhead of PHP‑FPM by keeping Laravel in memory behind a long‑running server. It shines for I/O‑heavy apps and busy APIs when you enforce stateless discipline, keep heavy work in queues, and measure the results. Start small in dev, add observability, then roll out behind your reverse proxy.
Top comments (0)