CLOUD
development

Laravel Octane on Your Server: When Performance Really Doubles, and When It's Not Worth It

CLOUD|September 19, 2026|7 min read|171 views
Laravel Octane on Your Server: When Performance Really Doubles, and When It's Not Worth It

Octane with Swoole keeps the app loaded in memory, lifting throughput from hundreds to thousands of requests per second. But it opens shared-state traps, needs server setup, and sometimes OPcache and query tuning are enough.

Laravel Octane fundamentally changes how your app runs. Instead of booting Laravel from scratch on every request (loading all files, building the container, reading config) then throwing it away at the end, Octane keeps the app loaded in memory through an application server like Swoole or FrankenPHP, so it serves each request from a pre-warmed instance. In practice: a typical app on PHP-FPM serving around 200 to 400 requests per second can jump with Octane and Swoole to 1,500 to 3,000 requests per second on the same hardware, an improvement that often ranges from 3x to 8x in the right scenarios, not merely a doubling. The direct answer: Octane is worth it when the biggest cost is repeated booting rather than the database, meaning apps with many light requests (APIs, active dashboards). But it is not worth the effort if your slowness comes from heavy queries, missing indexes, or a missing OPcache, because Octane will not speed up a slow query and may even hide a deeper problem. Most importantly, Octane opens a new class of bugs called memory state leakage, because you no longer start from a clean slate each request.

The core rule: before Octane, enable the free basics first (OPcache, query tuning, caching). If booting is still the bottleneck, that is when Octane gives you its real jump.

Why Octane speeds things up so much

In the traditional PHP-FPM model, every HTTP request goes through a full cycle: PHP reads tens of thousands of framework lines, builds the service container, registers service providers, reads config files, and only after all that runs a single line of your logic. This boot can consume 20 to 60 milliseconds per request even before touching the database.

Octane pays this cost once when the worker starts, then keeps the booted app in memory. The next request finds everything ready and begins straight at your logic. Swoole workers run on a non-blocking event loop model, and a single worker can serve thousands of connections. This is the source of the jump from hundreds to thousands of requests per second.

MetricTraditional PHP-FPMOctane + Swoole
Boot per request20 to 60 msOnce at worker start
Requests/sec (light API)~200 to 400~1,500 to 3,000
Response time (p50)High due to bootNoticeably lower
Execution modelProcess per requestResident worker with event loop

Shared-state traps in memory

This is the most dangerous part of Octane, and the reason some apps break on it although they run fine on PHP-FPM. Because the app stays alive between requests, any state you leave in memory leaks into the next request, and sometimes into a completely different user. Watch these sources:

  • Static properties: a static variable holding a user's data from an earlier request can surface for a later user. This is a data leak vulnerability, not just a performance bug.
  • Singletons holding request state: a service registered as a singleton where you stored the current user will keep that user for the next request.
  • Gradual memory leaks: data piling up in arrays or an in-process cache without cleanup grows worker consumption until it crashes. The fix is to recycle workers after a set number of requests (max_requests).
  • A polluted container: bindings you added to the container during a request persist to the next unless cleaned.

Octane provides events like RequestReceived and cleanup tasks, and it resets some services automatically, but it does not know your custom state. The rule: do not store request-specific state anywhere that lives longer than the request.

Setup requirements on an Ubuntu VPS

On a cloud server running Ubuntu, setting up Octane with Swoole is direct:

  • PHP 8.2 or newer with the Swoole extension via pecl install swoole, or use FrankenPHP which needs no PECL extension.
  • Install the package: composer require laravel/octane then php artisan octane:install.
  • Run the server behind Nginx as a reverse proxy that forwards requests to the Octane port.
  • Manage the process with supervisor or systemd for automatic restart on crash, and set worker count according to core count.
  • A practical worker rule: 2 to 4 workers per vCPU is a reasonable starting point, then tune by measuring.

How much resource you need

Because each worker holds a full copy of the app in memory, Octane consumes more memory than FPM. The Numuw plan (2vCPU/4GB) is a good starting point for a medium API, and the Aamaal plan (4vCPU/8GB) gives room for more workers and a wider cache. If you need extra memory, adding +2GB RAM for 600 SAR per year is a direct fix. See the pricing and plans for details.

When OPcache and query tuning are enough

Before you pay the cost of Octane's complexity, check whether your problem has a cheaper fix. The free tools often give you the largest share of the gain:

SolutionCostExpected gain
Enable OPcacheA config line, freeCaches compiled code, an immediate noticeable gain on any setup
Index slow queriesEXPLAIN analysis, freeTens to hundreds of times for one slow query
CachingSimple setupRemoves repeated computation entirely
Laravel OctaneServer setup + state code review3x to 8x for boot-heavy requests

The decisive rule: if your response time is spent by the app waiting on the database, Octane will not help because the problem is not the boot. Enable OPcache first (almost always a free gain), tune your queries with EXPLAIN, add a caching layer, then measure. If booting is still the bottleneck after that, Octane gives you its real jump without hiding a problem.

Octane runtimes: Swoole, FrankenPHP, and RoadRunner

Octane is a unified interface over three application servers, each with a different character:

RuntimeRequirementStands out for
SwooleA PECL extension on PHPMost mature performance, async tasks, timers, internal connection pools
FrankenPHPA single binary (built on the Caddy server)No PECL extension, supports HTTP/2, HTTP/3, and automatic TLS
RoadRunnerA binary written in GoStable, strong worker management, no PHP modification needed

Swoole gives the highest performance ceiling and richest features (concurrent execution, periodic in-process timers), but it is a PHP extension that needs root to install. FrankenPHP is the easiest to deploy because it is a single binary carrying the web server with it, and it gives you HTTP/3 without a separate Nginx setup. RoadRunner is a stable middle option for those who prefer isolating the worker layer from PHP itself. For most new cases, FrankenPHP is the shortest path to try it, and Swoole is the destination when you want the last drop of performance or its concurrent features.

How to benchmark before and after honestly

Do not believe an improvement you did not measure on your own load. Follow this method: fix a test scenario that resembles your real traffic (same routes and request ratios), run a load tool like wrk or k6 at a fixed concurrent connection count for at least a minute, and record three numbers: requests per second, response time at the 50th percentile (p50), and at the 95th percentile (p95) because it reveals the slow tail that users actually feel. Measure FPM first as a baseline, then Octane with exactly the same scenario on the same hardware. The real difference at p95 matters more than a shiny average, and a low p95 is what makes your app feel fast under pressure.

Practical conclusion

Decide in this sequence: first enable OPcache and measure with a tool like ab or wrk, second tune your slowest queries with EXPLAIN, third add caching for repeated data. If your throughput is still below your need and you see that booting consumes a large share of response time, try Octane in a test environment first, and review every static property and singleton for resident state before deploying. Set max_requests to recycle workers periodically as a safety net against memory leaks. And if you want a server with full root to install Swoole and tune workers freely, start from the Numuw plan on Riyadh servers with a response time near 8ms.

Share