Laravel Octane: State Leakage &amp; Memory Management | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Laravel Octane: Worker Lifecycle, State Leakage, and Memory Management in Production        On this page       1. [  Why Octane Changes Everything About PHP State ](#why-octane-changes-everything-about-php-state)
2. [  Phase 1 — Boot (once per worker) ](#phase-1-boot-once-per-worker)
3. [  Phase 2 — Request handling (once per request) ](#phase-2-request-handling-once-per-request)
4. [  Phase 3 — Cleanup (once per request, after response) ](#phase-3-cleanup-once-per-request-after-response)
5. [  The Three Categories of State Leakage ](#the-three-categories-of-state-leakage)
6. [  1. Singleton Accumulation ](#1-singleton-accumulation)
7. [  2. Static Property Pollution ](#2-static-property-pollution)
8. [  3. Eloquent Model Event Listeners Stacking ](#3-eloquent-model-event-listeners-stacking)
9. [  Memory Management Strategies ](#memory-management-strategies)
10. [  Worker Restart Thresholds ](#worker-restart-thresholds)
11. [  Monitoring Memory Per Request ](#monitoring-memory-per-request)
12. [  Identifying Leaks with gc\_collect\_cycles() ](#identifying-leaks-with-codegc-collect-cyclescode)
13. [  Practical Checklist Before Deploying to Octane ](#practical-checklist-before-deploying-to-octane)
14. [  Key Takeaways ](#key-takeaways)

  ![Laravel Octane: Worker Lifecycle, State Leakage, and Memory Management in Production](https://cdn.msaied.com/309/1ba16118f9db7f27c39cd9f3d693df44.png)

  #laravel   #octane   #performance   #php  

 Laravel Octane: Worker Lifecycle, State Leakage, and Memory Management in Production 
======================================================================================

     28 Jun 2026      4 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

  14 sections  

1. [  01   Why Octane Changes Everything About PHP State  ](#why-octane-changes-everything-about-php-state)
2. [  02   Phase 1 — Boot (once per worker)  ](#phase-1-boot-once-per-worker)
3. [  03   Phase 2 — Request handling (once per request)  ](#phase-2-request-handling-once-per-request)
4. [  04   Phase 3 — Cleanup (once per request, after response)  ](#phase-3-cleanup-once-per-request-after-response)
5. [  05   The Three Categories of State Leakage  ](#the-three-categories-of-state-leakage)
6. [  06   1. Singleton Accumulation  ](#1-singleton-accumulation)
7. [  07   2. Static Property Pollution  ](#2-static-property-pollution)
8. [  08   3. Eloquent Model Event Listeners Stacking  ](#3-eloquent-model-event-listeners-stacking)
9. [  09   Memory Management Strategies  ](#memory-management-strategies)
10. [  10   Worker Restart Thresholds  ](#worker-restart-thresholds)
11. [  11   Monitoring Memory Per Request  ](#monitoring-memory-per-request)
12. [  12   Identifying Leaks with gc\_collect\_cycles()  ](#identifying-leaks-with-codegc-collect-cyclescode)
13. [  13   Practical Checklist Before Deploying to Octane  ](#practical-checklist-before-deploying-to-octane)
14. [  14   Key Takeaways  ](#key-takeaways)

       Why Octane Changes Everything About PHP State
---------------------------------------------

Traditional PHP-FPM boots the framework on every request and discards all memory when the request ends. Octane inverts this: a single worker process boots Laravel once and handles thousands of requests in sequence. The performance gain is real, but the contract changes completely — **anything you store in a static property, a resolved singleton, or a class-level variable now persists across requests unless you explicitly reset it**.

Understanding the three phases of an Octane worker is the foundation for writing safe code.

### Phase 1 — Boot (once per worker)

The application container is instantiated, all service providers are registered and booted, and every singleton bound in `register()` is resolved on first use. This is the only phase where you pay the full framework bootstrap cost.

### Phase 2 — Request handling (once per request)

Octane clones the base container into a request-scoped sandbox, dispatches the HTTP kernel, and returns the response. The sandbox clone is shallow — it shares the same singleton instances that were resolved during boot unless you tell Octane to flush them.

### Phase 3 — Cleanup (once per request, after response)

Octane fires `RequestHandled`, runs its own flush callbacks, and discards the shallow clone. Singletons that were resolved during boot are **not** discarded here.

---

The Three Categories of State Leakage
-------------------------------------

### 1. Singleton Accumulation

A service that appends to an internal array on every request will grow without bound:

```php
class AuditCollector
{
    private array $events = [];

    public function record(string $event): void
    {
        $this->events[] = $event; // leaks across requests
    }
}

```

Fix: register a flush callback in your service provider.

```php
public function boot(Application $app): void
{
    $app->make(AuditCollector::class); // resolve early so Octane sees it

    Octane::flush(function () use ($app) {
        $app->make(AuditCollector::class)->reset();
    });
}

```

Alternatively, bind the service as `scoped` instead of `singleton`. Scoped bindings are re-resolved on every request inside the sandbox:

```php
$this->app->scoped(AuditCollector::class);

```

### 2. Static Property Pollution

Static properties bypass the container entirely, so `scoped` bindings do not help:

```php
class FeatureFlags
{
    private static array $cache = [];

    public static function get(string $flag): bool
    {
        if (!isset(self::$cache[$flag])) {
            self::$cache[$flag] = DB::table('flags')->where('name', $flag)->value('enabled');
        }
        return (bool) self::$cache[$flag];
    }
}

```

This is fine for immutable config, but dangerous if flags can change mid-deployment. Register an Octane flush callback that calls `self::$cache = []`, or replace the static cache with a request-scoped service.

### 3. Eloquent Model Event Listeners Stacking

If you call `Model::creating(fn () => ...)` inside a request (e.g., in a controller or action), the closure is appended to the model's static dispatcher on every request. After 1 000 requests, 1 000 listeners fire for each `creating` event.

Always register model observers and event listeners in service providers during boot, never inside request handlers.

---

Memory Management Strategies
----------------------------

### Worker Restart Thresholds

Octane's `--max-requests` flag restarts a worker after N requests, reclaiming all memory:

```bash
php artisan octane:start --max-requests=500

```

This is a safety net, not a substitute for fixing leaks. A well-written Octane app should be stable at 10 000+ requests per worker.

### Monitoring Memory Per Request

Add a terminating middleware that logs memory growth:

```php
public function terminate(Request $request, Response $response): void
{
    $mb = round(memory_get_usage(true) / 1_048_576, 2);
    logger()->channel('octane')->debug('memory', ['mb' => $mb, 'path' => $request->path()]);
}

```

A flat line across requests means no leakage. A rising sawtooth means something is accumulating.

### Identifying Leaks with `gc_collect_cycles()`

Circular references between objects are not freed by PHP's reference-counting GC. Octane does not call `gc_collect_cycles()` automatically. Add it to your flush callback for memory-sensitive workers:

```php
Octane::flush(function () {
    gc_collect_cycles();
});

```

---

Practical Checklist Before Deploying to Octane
----------------------------------------------

- Audit every `singleton` binding: does it accumulate state? Switch to `scoped` or add a flush callback.
- Search for `static $` properties in domain code. Decide if they are truly immutable.
- Move all model observer and event listener registration to service providers.
- Set `--max-requests` as a backstop, not a crutch.
- Add per-request memory logging in staging before promoting to production.
- Test with `php artisan octane:start` locally and run your full test suite against the live worker.

---

Key Takeaways
-------------

- Octane workers are long-lived; PHP's request-scoped memory model no longer applies.
- Use `scoped` bindings for services that must be fresh each request.
- Static properties require explicit flush callbacks — the container cannot help you.
- Never register model listeners inside request handlers.
- Memory monitoring and `--max-requests` are complementary, not interchangeable.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-octane-worker-lifecycle-state-leakage-and-memory-management-in-production&text=Laravel+Octane%3A+Worker+Lifecycle%2C+State+Leakage%2C+and+Memory+Management+in+Production) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-octane-worker-lifecycle-state-leakage-and-memory-management-in-production) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  What is the difference between `singleton` and `scoped` in an Octane context?        A `singleton` is resolved once per worker process and shared across all requests. A `scoped` binding is re-resolved for each request inside Octane's sandbox clone, giving you a fresh instance per request without the overhead of a full container re-boot. 

      Q02  Does `--max-requests` fix state leakage?        It mitigates the impact by periodically recycling workers, but it does not fix the underlying leak. A worker restarted every 500 requests can still serve corrupted state to requests 2 through 499. Proper flush callbacks and scoped bindings are the correct solution. 

      Q03  Are third-party packages safe to use with Octane?        Not automatically. Any package that stores state in static properties or appends to singleton collections can leak. Check the package's Octane compatibility notes, and if absent, audit its service provider and any static usage manually before deploying. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![Advanced Authorization in Laravel: Gates, Policies, and Response-Based Access Control](https://cdn.msaied.com/308/669314d08f232d4d1e761e92fb9d9247.png) laravel authorization security 

### Advanced Authorization in Laravel: Gates, Policies, and Response-Based Access Control

Go beyond simple boolean gates. Learn how to use Policy responses, before hooks, and contextual authorization...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 27 Jun 2026     4 min read  

  Read    

 ](https://msaied.com/articles/advanced-authorization-in-laravel-gates-policies-and-response-based-access-control-1) [ ![Advanced Eloquent Casts: Custom Cast Classes, Value Objects, and Inbound-Only Transforms](https://cdn.msaied.com/307/d9832b90141b009f63e8e55ea856cb3a.png) laravel eloquent value-objects 

### Advanced Eloquent Casts: Custom Cast Classes, Value Objects, and Inbound-Only Transforms

Go beyond built-in Eloquent casts. Learn to build custom cast classes, wrap primitives in value objects, and a...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 27 Jun 2026     4 min read  

  Read    

 ](https://msaied.com/articles/advanced-eloquent-casts-custom-cast-classes-value-objects-and-inbound-only-transforms) [ ![Advanced Filament: Custom Field Plugins, Custom Columns, and Render Hooks](https://cdn.msaied.com/306/bfb43236ced4112cc9dab99a3eee82d2.png) filament laravel php 

### Advanced Filament: Custom Field Plugins, Custom Columns, and Render Hooks

Go beyond built-in components: build a reusable Filament custom field plugin, a typed custom column, and wire...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 27 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/advanced-filament-custom-field-plugins-custom-columns-and-render-hooks) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
