Laravel Octane FrankenPHP: Safe Singletons &amp; State | 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 Services, Boot-Once Singletons, and Safe State        On this page       1. [  The Problem Nobody Warns You About ](#the-problem-nobody-warns-you-about)
2. [  How the Container Lifetime Works ](#how-the-container-lifetime-works)
3. [  Identifying Dangerous Singletons ](#identifying-dangerous-singletons)
4. [  The Correct Pattern: Request-Scoped Bindings ](#the-correct-pattern-request-scoped-bindings)
5. [  Boot-Once Singletons: Maximising the Warm-Up Benefit ](#boot-once-singletons-maximising-the-warm-up-benefit)
6. [  Detecting Leaks in Tests ](#detecting-leaks-in-tests)
7. [  FrankenPHP-Specific Considerations ](#frankenphp-specific-considerations)
8. [  Takeaways ](#takeaways)

  ![Laravel Octane + FrankenPHP: Persistent Services, Boot-Once Singletons, and Safe State](https://cdn.msaied.com/486/7a50572cb8b282ae36063a9213f55ed3.png)

  #laravel   #octane   #frankenphp   #performance   #architecture  

 Laravel Octane + FrankenPHP: Persistent Services, Boot-Once Singletons, and Safe State 
========================================================================================

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

       Table of contents

1. [  01   The Problem Nobody Warns You About  ](#the-problem-nobody-warns-you-about)
2. [  02   How the Container Lifetime Works  ](#how-the-container-lifetime-works)
3. [  03   Identifying Dangerous Singletons  ](#identifying-dangerous-singletons)
4. [  04   The Correct Pattern: Request-Scoped Bindings  ](#the-correct-pattern-request-scoped-bindings)
5. [  05   Boot-Once Singletons: Maximising the Warm-Up Benefit  ](#boot-once-singletons-maximising-the-warm-up-benefit)
6. [  06   Detecting Leaks in Tests  ](#detecting-leaks-in-tests)
7. [  07   FrankenPHP-Specific Considerations  ](#frankenphp-specific-considerations)
8. [  08   Takeaways  ](#takeaways)

 The Problem Nobody Warns You About
----------------------------------

When you move a Laravel application from PHP-FPM to Octane (whether backed by Swoole, RoadRunner, or FrankenPHP), the process no longer dies after each request. The service container is booted once and reused. That is the entire source of the performance gain — and the entire source of subtle bugs.

Understanding *which* bindings survive across requests, *which* must be re-resolved per request, and *how* to enforce that boundary is the difference between a stable production deployment and a system that leaks user data between sessions.

How the Container Lifetime Works
--------------------------------

Octane boots the application once in the worker process, then for each incoming request it:

1. Creates a **sandbox clone** of the container.
2. Re-binds a small set of core request-aware services (`Request`, `Auth`, `Session`, `Cookie`, etc.).
3. Runs your route/middleware stack against the sandbox.
4. Discards the sandbox after the response is sent.

The *base* container — and every singleton registered in a service provider's `register()` method — persists for the lifetime of the worker.

```php
// This singleton is booted ONCE and shared across every request.
// Safe only if it holds no per-request state.
$this->app->singleton(ReportRenderer::class, function () {
    return new ReportRenderer(config('reports'));
});

```

If `ReportRenderer` caches a reference to the current `Auth::user()` internally, you have a data-leak bug.

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

The rule is simple: **a singleton is safe if its constructor and methods are pure with respect to request identity**. Danger signs:

- Storing `$this->user = auth()->user()` in a property.
- Injecting `Request` via the constructor (not a closure).
- Caching database results in an instance property without a TTL.
- Holding an open database transaction reference.

Octane ships with a `octane:check` command (Laravel 11+) that statically warns about some of these, but it cannot catch everything.

The Correct Pattern: Request-Scoped Bindings
--------------------------------------------

For services that *must* know about the current request, register them as **scoped** bindings. Octane flushes scoped bindings between requests automatically.

```php
// ServiceProvider::register()
$this->app->scoped(CurrentTenant::class, function (Application $app) {
    return new CurrentTenant(
        $app->make(Request::class)->header('X-Tenant-ID')
    );
});

```

`scoped()` behaves like `singleton()` within a single request lifecycle but is re-resolved on the next request. This is the correct tool for anything tenant-aware, user-aware, or request-context-aware.

Boot-Once Singletons: Maximising the Warm-Up Benefit
----------------------------------------------------

For genuinely stateless, expensive-to-construct services — compiled Twig environments, parsed config trees, HTTP client pools — you *want* them to survive across requests. Make that intent explicit:

```php
$this->app->singleton(CompiledRuleEngine::class, function () {
    // Expensive: parses 400 YAML rule files.
    return RuleEngineFactory::fromDisk(storage_path('rules'));
});

```

Document this in a `@octane-persistent` docblock annotation (a convention, not a framework feature) so future maintainers know the class must remain stateless.

Detecting Leaks in Tests
------------------------

With Pest, you can assert that a scoped binding is not accidentally promoted to a singleton:

```php
it('resolves a fresh CurrentTenant per request sandbox', function () {
    $app = app();

    $first = $app->make(CurrentTenant::class);
    // Simulate Octane flushing scoped instances.
    $app->forgetScopedInstances();
    $second = $app->make(CurrentTenant::class);

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

```

`forgetScopedInstances()` is the same method Octane calls internally between requests, making this a faithful unit test.

FrankenPHP-Specific Considerations
----------------------------------

FrankenPHP's worker mode runs the Laravel bootstrap inside a loop. Unlike Swoole, it does not use coroutines, so there is no concurrent request sharing within a single worker. However, the same singleton lifetime rules apply. One additional concern: **static class properties** are never reset by Octane's sandbox mechanism. If a third-party package accumulates state in a static array, you must reset it manually via Octane's `RequestHandled` event:

```php
use Laravel\Octane\Events\RequestHandled;

Event::listen(RequestHandled::class, function () {
    SomePackage::resetStaticCache();
});

```

Takeaways
---------

- Use `singleton()` only for stateless, request-identity-free services.
- Use `scoped()` for anything that touches auth, tenancy, or the current request.
- `forgetScopedInstances()` in Pest tests faithfully simulates Octane's request boundary.
- Static class properties bypass Octane's sandbox — reset them via `RequestHandled`.
- Run `php artisan octane:check` as a CI step, but treat it as a starting point, not a guarantee.

 Found this useful?

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

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

  3 questions  

     Q01  What is the difference between singleton() and scoped() in Laravel Octane?        singleton() resolves once and caches the instance for the entire worker lifetime — across all requests. scoped() also caches within a single request, but Octane flushes it between requests. Use scoped() for anything that depends on the current user, tenant, or HTTP request context. 

      Q02  Does FrankenPHP worker mode behave differently from Swoole regarding state leakage?        The container lifetime rules are identical. FrankenPHP does not use coroutines, so there is no intra-worker concurrency concern, but singletons still persist across requests. Static class properties are also unaffected by Octane's sandbox in both runtimes and must be reset manually. 

      Q03  How can I detect accidental singleton promotion in a Pest test suite?        Call app()-&gt;forgetScopedInstances() between two make() calls in your test. If both calls return the same object instance, the binding was registered as a singleton instead of scoped. This mirrors exactly what Octane does between real HTTP requests. 

  Continue reading

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

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

 [ ![Practical RAG in Laravel: pgvector, Embeddings, and Retrieval Pipelines](https://cdn.msaied.com/487/2db17c4f7927d4a229a4786c03e7b67b.png) laravel ai pgvector 

### Practical RAG in Laravel: pgvector, Embeddings, and Retrieval Pipelines

Build a production-ready retrieval-augmented generation pipeline in Laravel using pgvector, OpenAI embeddings,...

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

 30 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/practical-rag-in-laravel-pgvector-embeddings-and-retrieval-pipelines-2) [ ![Everything Announced at Laracon US 2026: Laravel Framework, Cloud & AI Updates](https://cdn.msaied.com/485/8c49e044ff45a776167065579e1c93ac.png) Laracon 2026 Laravel Cloud Laravel AI SDK 

### Everything Announced at Laracon US 2026: Laravel Framework, Cloud &amp; AI Updates

Laracon US 2026 brought major updates across the Laravel ecosystem: scale-to-zero Flex compute, managed queues...

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

 29 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/everything-announced-at-laracon-us-2026-laravel-framework-cloud-ai-updates) [ ![Laravel Queues at Scale: Backpressure, Dead-Letter Patterns, and Job Observability](https://cdn.msaied.com/484/7ee0710bfc61c6ff7667dd4f60a8c5bd.png) laravel queues observability 

### Laravel Queues at Scale: Backpressure, Dead-Letter Patterns, and Job Observability

Beyond basic queue workers: learn how to implement backpressure signals, dead-letter queues, and structured jo...

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

 29 Jul 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-queues-at-scale-backpressure-dead-letter-patterns-and-job-observability) 

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