FrankenPHP Worker Mode: Safe State in Laravel Octane | 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 + FrankenPHP: Persistent State, Shared Services, and Safe Bootstrapping        On this page       1. [  Why Worker Mode Changes Everything ](#why-worker-mode-changes-everything)
2. [  The Lifecycle You Must Internalize ](#the-lifecycle-you-must-internalize)
3. [  Identifying Dangerous Singletons ](#identifying-dangerous-singletons)
4. [  Registering Octane Flush Callbacks ](#registering-octane-flush-callbacks)
5. [  Static Properties: The Hidden Landmine ](#static-properties-the-hidden-landmine)
6. [  Safe Bootstrapping Pattern ](#safe-bootstrapping-pattern)
7. [  Key Takeaways ](#key-takeaways)

  ![Laravel Octane + FrankenPHP: Persistent State, Shared Services, and Safe Bootstrapping](https://cdn.msaied.com/224/cc0aa09965b63e7311e93282849ada05.png)

  #laravel   #octane   #frankenphp   #performance   #architecture  

 Laravel Octane + FrankenPHP: Persistent State, Shared Services, and Safe Bootstrapping 
========================================================================================

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

       Table of contents

1. [  01   Why Worker Mode Changes Everything  ](#why-worker-mode-changes-everything)
2. [  02   The Lifecycle You Must Internalize  ](#the-lifecycle-you-must-internalize)
3. [  03   Identifying Dangerous Singletons  ](#identifying-dangerous-singletons)
4. [  04   Registering Octane Flush Callbacks  ](#registering-octane-flush-callbacks)
5. [  05   Static Properties: The Hidden Landmine  ](#static-properties-the-hidden-landmine)
6. [  06   Safe Bootstrapping Pattern  ](#safe-bootstrapping-pattern)
7. [  07   Key Takeaways  ](#key-takeaways)

 Why Worker Mode Changes Everything
----------------------------------

FrankenPHP's worker mode keeps your Laravel application bootstrapped in memory across thousands of requests. The PHP process never dies between requests — the container, service providers, and any resolved singletons all persist. That is the source of the throughput gain, and the source of every subtle bug you will spend a weekend debugging.

This article focuses on the practical discipline required to write application code that is safe under these conditions.

---

The Lifecycle You Must Internalize
----------------------------------

Under a traditional PHP-FPM setup, every request gets a fresh process. Under FrankenPHP worker mode (or Laravel Octane with any driver), the lifecycle looks like this:

1. **Bootstrap** — runs once when the worker starts.
2. **Request loop** — `$kernel->handle()` runs for each request on the same container instance.
3. **Flush** — Octane fires `octane:request-handled` and resets registered services.

Octane's `RequestHandled` event triggers its own cleanup, but only for services it knows about. Anything you bind yourself is your responsibility.

---

Identifying Dangerous Singletons
--------------------------------

A singleton is dangerous in worker mode when it holds **request-scoped state** — authenticated user, request headers, per-request configuration, or accumulated data.

```php
// DANGEROUS: holds the resolved user across requests
app()->singleton(CurrentUser::class, function ($app) {
    return new CurrentUser(
        $app['auth']->user() // resolved at bind time, not request time
    );
});

```

The fix is to make the resolution lazy and request-aware:

```php
// SAFE: resolves fresh on every call
app()->bind(CurrentUser::class, function ($app) {
    return new CurrentUser($app['auth']->user());
});

```

If you genuinely need a singleton for performance (e.g., a compiled rule set), separate the **immutable config** from the **mutable state**:

```php
app()->singleton(PricingEngine::class, function ($app) {
    // Rules loaded once from cache — safe, immutable
    return new PricingEngine(PricingRules::fromCache());
});

```

---

Registering Octane Flush Callbacks
----------------------------------

Octane exposes `Octane::flush()` for registering cleanup callbacks that run after every request:

```php
use Laravel\Octane\Facades\Octane;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Octane::flush([
            CurrentUser::class,
            TenantContext::class,
        ]);

        // Or a closure for finer control
        Octane::afterRequest(function () {
            app(MetricsCollector::class)->flush();
        });
    }
}

```

The array form calls `app()->forgetInstance()` on each class. The closure form lets you do custom teardown — flushing buffers, resetting static properties, or clearing in-memory queues.

---

Static Properties: The Hidden Landmine
--------------------------------------

Octane's flush mechanism cannot reset PHP static properties. If you have:

```php
class QueryLogger
{
    private static array $log = [];

    public static function record(string $sql): void
    {
        self::$log[] = $sql;
    }
}

```

`$log` grows unbounded across every request in the worker. The fix is to register a reset in your `afterRequest` hook:

```php
Octane::afterRequest(function () {
    QueryLogger::reset(); // clears the static array
});

```

Alternatively, move the state into a container-bound service that Octane can flush.

---

Safe Bootstrapping Pattern
--------------------------

For services that are expensive to construct but safe to share (database connection pools, compiled Twig environments, ML model handles), use a two-phase pattern:

```php
class InferenceServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Singleton: model weights loaded once
        $this->app->singleton(EmbeddingModel::class, fn() =>
            EmbeddingModel::loadFromDisk(config('ai.model_path'))
        );
    }

    public function boot(): void
    {
        // Per-request context wraps the singleton safely
        $this->app->bind(EmbeddingContext::class, fn($app) =>
            new EmbeddingContext($app->make(EmbeddingModel::class))
        );
    }
}

```

The heavy model is a singleton. The context — which may hold per-request token counts or user preferences — is bound (not singleton), so it is reconstructed fresh each request.

---

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

- **`bind` vs `singleton`** is now a correctness decision, not just a performance one.
- Use `Octane::flush([...])` and `Octane::afterRequest(...)` to register explicit teardown for every stateful service.
- Static class properties bypass Octane's flush — reset them manually or eliminate them.
- Separate immutable configuration (safe to share) from mutable request context (must be rebound).
- Test worker-mode safety by running your test suite with `OCTANE_TESTING=true` and asserting no state leaks between simulated requests.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-octane-frankenphp-persistent-state-shared-services-and-safe-bootstrapping&text=Laravel+Octane+%2B+FrankenPHP%3A+Persistent+State%2C+Shared+Services%2C+and+Safe+Bootstrapping) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-octane-frankenphp-persistent-state-shared-services-and-safe-bootstrapping) 

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

  3 questions  

     Q01  Does FrankenPHP worker mode require Laravel Octane?        Yes. FrankenPHP's worker mode integrates with Laravel through the Octane package, which manages the request loop, lifecycle events, and flush callbacks. Without Octane, you would need to implement the worker loop and teardown yourself. 

      Q02  How do I test for state leaks between requests in worker mode?        Octane ships with a `withOctane()` test helper and a `OctaneTestCase` base. You can simulate multiple sequential requests in a single test and assert that state from request one does not bleed into request two. Also audit any `static` properties and container singletons that hold mutable data. 

      Q03  Is it safe to use Laravel's Auth facade in a singleton resolved at boot time?        No. The Auth facade resolves the guard lazily, but if you resolve `auth()-&gt;user()` inside a singleton's constructor at boot, you capture a null or stale user for the lifetime of the worker. Always resolve the authenticated user inside a `bind` (per-request) service or directly within the controller/action. 

  Continue reading

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

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

 [ ![PhpStorm 2026.2 Released: Laravel Tool Window, PHP 8.5 Pipe Operator, and AI Agents](https://cdn.msaied.com/505/151a0bba66cc27064e090e69e55d7c92.png) PhpStorm JetBrains PHP 8.5 

### PhpStorm 2026.2 Released: Laravel Tool Window, PHP 8.5 Pipe Operator, and AI Agents

PhpStorm 2026.2 ships a dedicated Laravel tool window with Artisan, error logs, and Laravel Cloud tabs, plus P...

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

 3 Aug 2026     3 min read  

  Read    

 ](https://msaied.com/articles/phpstorm-20262-released-laravel-tool-window-php-85-pipe-operator-and-ai-agents) [ ![Laravel Doctor: Diagnose Your Laravel App With One Artisan Command](https://cdn.msaied.com/504/d72224689abc7b396bce187535008272.png) Laravel Artisan Health Checks 

### Laravel Doctor: Diagnose Your Laravel App With One Artisan Command

Laravel Doctor is a first-party package announced at Laracon US 2026 that adds an `artisan doctor` command to...

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

 3 Aug 2026     4 min read  

  Read    

 ](https://msaied.com/articles/laravel-doctor-diagnose-your-laravel-app-with-one-artisan-command) [ ![Livewire v4.3.5 Released: Fix for SFC Detection with PHP Attribute Array Arguments](https://cdn.msaied.com/503/9678ed8dbf5d7a6f4f19ca7694cf241b.png) Livewire Laravel PHP 

### Livewire v4.3.5 Released: Fix for SFC Detection with PHP Attribute Array Arguments

Livewire v4.3.5 ships a targeted bug fix for Single File Component (SFC) detection when PHP attributes contain...

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

 3 Aug 2026     2 min read  

  Read    

 ](https://msaied.com/articles/livewire-v435-released-fix-for-sfc-detection-with-php-attribute-array-arguments) 

   [  ![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)
