Octane Speeds Laravel Up by Breaking an Assumption
Every request in a normal Laravel application starts from nothing. Octane keeps the application in memory between requests, which is where the speed comes from and where the bugs come from too.
The thing that makes PHP forgiving is that it forgets. A request arrives, the framework boots, the work happens, the process exits, and every variable created along the way disappears. A memory leak lasts milliseconds. A static property polluted with one user's data is gone before the next user arrives.
Octane removes that. The application boots once and stays in memory, handling request after request in the same process. Skipping the boot is where the speed comes from - and the forgetting was load-bearing in ways most codebases have never had to think about.
What stops being true
Static properties persist. A static cache that was per-request is now shared by every request the worker handles. If it is keyed by user, it is a data leak.
Singletons outlive the request that created them. A service resolved once and registered as a singleton will hold whatever it captured at first resolution - including, in the worst case, a request or an authenticated user.
Globals persist. Anything written to a superglobal or a global variable survives.
Leaks accumulate. An array that grows a little on each request used to be free. Now the worker's memory climbs until something restarts it.
The pattern that actually bites
It is rarely a static array. It is a service that took a dependency it should have resolved later:
// AppServiceProvider
$this->app->singleton(ReportBuilder::class, function ($app) {
return new ReportBuilder($app->make(Request::class));
});Registered as a singleton, this captures the first request the worker ever handles and keeps it. Every subsequent request gets a builder holding somebody else's input.
Under normal PHP this is harmless - the process dies, the singleton dies with it, and nobody ever notices the latent bug. Under Octane it is a cross-user data leak that appears intermittently and is almost impossible to reproduce from a report.
The fix is to resolve per-request state when it is needed rather than when the service is built:
$this->app->singleton(ReportBuilder::class, fn () => new ReportBuilder());
// and inside the method that needs it
public function build(Request $request): Report { ... }The same applies to anything that captures the authenticated user, the current tenant, or the locale at construction time. On a multi-tenant platform this moves from an embarrassment to a serious incident, because the boundary between tenants is exactly what is being crossed.
Finding them before production does
Read the service providers first. Every singleton binding, and every
bind whose closure resolves something request-shaped, is a candidate.
Then search for static properties that are written to rather than only read:
grep -rn "protected static \|private static \|public static " app/ | grep -v "function\|const"Most will be legitimate. The ones that hold data rather than configuration are the list to work through.
Laravel provides hooks to reset state between requests, and packages register their own. They cover the framework's own services well and they know nothing about yours.
The part that is not about correctness
Even with the state handled, a long-running process has a different operational shape.
Memory has to be watched over hours, not minutes - a leak of a hundred kilobytes per request is invisible in a test and fatal overnight. Workers need a maximum request count so they are recycled before they degrade. And a deploy has to restart them, which is the same lesson as with queue workers: a long-lived process holds the code it booted with, so new code does not reach it until something makes it exit.
Is it worth it
Sometimes, and less often than the benchmarks suggest.
The boot is what Octane removes, and a request whose time goes on a slow query or a third-party call gains nothing at all. Profile a real endpoint first. If framework boot is a meaningful share of your response time, the gain is real; if the database is, fix the database.
And if the application has singletons capturing request state, fix those regardless of what you decide about Octane. They are bugs today - they are just bugs that PHP has been quietly covering for.
On a multi-tenant platform, a captured tenant crosses the one boundary the product is sold on. It is the most expensive version of this bug. Restarting the workers on deploy closes the other one, for the reason set out here.
Whether the boot is actually costing you anything is a measurement, and it is the first thing we do.
