Laravel Octane FrankenPHP Safe Singleton Patterns | 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: Shared State, Request Isolation, and Safe Singleton Patterns        On this page       1. [  The Problem With Long-Lived Workers ](#the-problem-with-long-lived-workers)
2. [  Scoped Bindings: The Right Tool ](#scoped-bindings-the-right-tool)
3. [  When scoped() Is Not Enough ](#when-codescopedcode-is-not-enough)
4. [  Flush Hooks for Third-Party Singletons ](#flush-hooks-for-third-party-singletons)
5. [  Detecting Leaks Before Production ](#detecting-leaks-before-production)
6. [  Safe Patterns at a Glance ](#safe-patterns-at-a-glance)
7. [  Takeaways ](#takeaways)

  ![Laravel Octane + FrankenPHP: Shared State, Request Isolation, and Safe Singleton Patterns](https://cdn.msaied.com/349/e8f1b783afac1995d090c041f705d8c5.png)

  #laravel   #octane   #frankenphp   #performance   #architecture  

 Laravel Octane + FrankenPHP: Shared State, Request Isolation, and Safe Singleton Patterns 
===========================================================================================

     3 Jul 2026      4 min read    ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)  Mohamed Said  

       Table of contents

1. [  01   The Problem With Long-Lived Workers  ](#the-problem-with-long-lived-workers)
2. [  02   Scoped Bindings: The Right Tool  ](#scoped-bindings-the-right-tool)
3. [  03   When scoped() Is Not Enough  ](#when-codescopedcode-is-not-enough)
4. [  04   Flush Hooks for Third-Party Singletons  ](#flush-hooks-for-third-party-singletons)
5. [  05   Detecting Leaks Before Production  ](#detecting-leaks-before-production)
6. [  06   Safe Patterns at a Glance  ](#safe-patterns-at-a-glance)
7. [  07   Takeaways  ](#takeaways)

 The Problem With Long-Lived Workers
-----------------------------------

Traditional PHP-FPM boots the framework on every request and discards everything afterward. Octane — whether backed by Swoole, RoadRunner, or FrankenPHP — keeps a single worker process alive across thousands of requests. That is the source of its speed advantage, and the source of its most subtle bugs.

When you bind a class as a singleton in a service provider, that instance persists for the lifetime of the worker. Any mutable state it holds bleeds from one request into the next.

```php
// AppServiceProvider.php — dangerous under Octane
$this->app->singleton(CartService::class, function () {
    return new CartService(); // holds $this->items = []
});

```

Request A adds items to the cart. Request B — from a completely different user — resolves the same `CartService` instance and sees Request A's items. This is a classic Octane state-leak.

Scoped Bindings: The Right Tool
-------------------------------

Laravel ships a first-class solution: `scoped()`. A scoped binding behaves like a singleton within a single request lifecycle, then is flushed automatically by Octane between requests.

```php
// Correct: scoped to one request
$this->app->scoped(CartService::class, function () {
    return new CartService();
});

```

Octane calls `$app->forgetScopedInstances()` at the end of every request, so the next request gets a fresh instance. No manual cleanup required.

### When `scoped()` Is Not Enough

Some objects are legitimately shared across requests — database connection pools, compiled route collections, config repositories. The rule of thumb:

- **Stateless or immutable** → `singleton()` is fine.
- **Mutable, request-specific** → use `scoped()`.
- **Mutable, shared intentionally** → use `singleton()` but make mutation thread-safe (Swoole) or accept that FrankenPHP workers are isolated processes.

FrankenPHP's worker mode uses separate PHP fibers per request within the same process, so true shared memory between concurrent requests is not a concern the way it is with Swoole coroutines. However, sequential requests in the same worker still share the same singleton instances.

Flush Hooks for Third-Party Singletons
--------------------------------------

You do not always control whether a package registers a singleton or a scoped binding. Octane provides flush hooks to reset specific instances between requests.

```php
// config/octane.php
'flush' => [
    \App\Services\ReportBuilder::class,
],

```

For more granular control, listen to the `RequestReceived` and `RequestTerminated` Octane events:

```php
use Laravel\Octane\Events\RequestReceived;
use Laravel\Octane\Events\RequestTerminated;

Event::listen(RequestReceived::class, function ($event) {
    $event->sandbox->forgetInstance(ReportBuilder::class);
});

```

`$event->sandbox` is the per-request application clone Octane creates — mutating it does not affect the master container.

Detecting Leaks Before Production
---------------------------------

Octane ships with a `--watch` flag for development, but it will not surface state leaks automatically. A practical detection pattern is to inject a unique request ID into any suspicious singleton and assert it changes between requests in a test:

```php
it('creates a fresh CartService per request', function () {
    $first = $this->get('/cart')->json('session_id');
    $second = $this->get('/cart')->json('session_id');

    expect($first)->not->toBe($second);
});

```

For deeper inspection, Telescope's request watcher combined with a custom `Octane:RequestTerminated` listener that dumps resolved instances is invaluable during staging.

Safe Patterns at a Glance
-------------------------

```php
// 1. Immutable value object — singleton is fine
$this->app->singleton(CurrencyFormatter::class);

// 2. Request-scoped accumulator — use scoped
$this->app->scoped(AuditLog::class);

// 3. External client with connection pool — singleton, but reset on error
$this->app->singleton(RedisClient::class, fn() => new RedisClient(config('redis')));

```

Takeaways
---------

- Use `scoped()` for any service that accumulates request-specific state; Octane flushes it automatically.
- `singleton()` is safe only for stateless or intentionally shared objects.
- FrankenPHP workers are isolated processes, not coroutines — concurrent request bleed is sequential, not parallel.
- Octane's `flush` config key and `RequestReceived` event are your escape hatches for third-party singletons.
- Write a simple request-ID test to catch leaks before they reach production.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-octane-frankenphp-shared-state-request-isolation-and-safe-singleton-patterns&text=Laravel+Octane+%2B+FrankenPHP%3A+Shared+State%2C+Request+Isolation%2C+and+Safe+Singleton+Patterns) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-octane-frankenphp-shared-state-request-isolation-and-safe-singleton-patterns) 

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

  3 questions  

     Q01  What is the difference between singleton() and scoped() in Laravel Octane?        A singleton() persists for the entire worker lifetime across all requests. A scoped() binding behaves like a singleton within a single request and is automatically flushed by Octane between requests, preventing state from leaking to the next user. 

      Q02  Does FrankenPHP have the same concurrency risks as Swoole coroutines?        No. FrankenPHP uses separate PHP fibers per request within a worker process, so concurrent requests do not share memory the way Swoole coroutines can. However, sequential requests in the same worker still share singleton instances, so scoped bindings are still essential. 

      Q03  How do I reset a third-party package's singleton between Octane requests?        Add the class to the flush array in config/octane.php, or listen to the Octane RequestReceived event and call $event-&gt;sandbox-&gt;forgetInstance(YourClass::class) to drop the instance before the next request resolves it. 

  Continue reading

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

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

 [ ![Laravel AI SDK and Laravel MCP Security Fixes: Update Now](https://cdn.msaied.com/722/fbe8df92faa32e9b9cee984a18bd4411.png) security laravel-ai laravel-mcp 

### Laravel AI SDK and Laravel MCP Security Fixes: Update Now

Two security advisories were published for laravel/ai and laravel/mcp on September 30, 2026. Both are fixed—ru...

  ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)  Mohamed Said 

 30 Sep 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-ai-sdk-and-laravel-mcp-security-fixes-update-now) [ ![Migrating Pinkary from Laravel Forge to Laravel Cloud: An Engineering Playbook](https://cdn.msaied.com/723/6f9c9010ccb06581b52bcfab81e47dd9.png) Laravel Cloud Laravel Forge MySQL 

### Migrating Pinkary from Laravel Forge to Laravel Cloud: An Engineering Playbook

A code-backed walkthrough of the real issues encountered moving Pinkary from Laravel Forge to Laravel Cloud: S...

  ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)  Mohamed Said 

 30 Sep 2026     5 min read  

  Read    

 ](https://msaied.com/articles/migrating-pinkary-from-laravel-forge-to-laravel-cloud-an-engineering-playbook) [ ![PostgreSQL Recursive CTEs in Laravel: Hierarchical Data Without the ORM Gymnastics](https://cdn.msaied.com/720/3e3d256d54dd4036099122e0b035e482.png) laravel postgresql eloquent 

### PostgreSQL Recursive CTEs in Laravel: Hierarchical Data Without the ORM Gymnastics

Recursive CTEs let PostgreSQL walk tree structures in a single query. Learn how to wire them into Laravel's qu...

  ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)  Mohamed Said 

 30 Sep 2026     2 min read  

  Read    

 ](https://msaied.com/articles/postgresql-recursive-ctes-in-laravel-hierarchical-data-without-the-orm-gymnastics) 

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