<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rodrigo Vieira</title>
    <description>The latest articles on DEV Community by Rodrigo Vieira (@rodrigovieira92).</description>
    <link>https://dev.to/rodrigovieira92</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4009889%2F2d031254-f991-4bce-a805-377f892f3767.jpg</url>
      <title>DEV Community: Rodrigo Vieira</title>
      <link>https://dev.to/rodrigovieira92</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rodrigovieira92"/>
    <language>en</language>
    <item>
      <title>I built a pure-PHP HTTP server that handles 1,000,000+ requests/second — no C extension</title>
      <dc:creator>Rodrigo Vieira</dc:creator>
      <pubDate>Tue, 30 Jun 2026 16:45:32 +0000</pubDate>
      <link>https://dev.to/rodrigovieira92/i-built-a-pure-php-http-server-that-handles-1000000-requestssecond-no-c-extension-2j5c</link>
      <guid>https://dev.to/rodrigovieira92/i-built-a-pure-php-http-server-that-handles-1000000-requestssecond-no-c-extension-2j5c</guid>
      <description>&lt;p&gt;Every PHP developer has heard some version of it: &lt;em&gt;"PHP doesn't do concurrency."&lt;/em&gt; The mental model is shared-nothing, one request per process, boot the framework, die, repeat. For anything that needs real throughput, the standard advice is Nginx + PHP-FPM — or, if you want true async, reach for &lt;strong&gt;Swoole&lt;/strong&gt;, a C extension you compile into PHP.&lt;/p&gt;

&lt;p&gt;I've spent a while building &lt;strong&gt;&lt;a href="https://github.com/bootgly/bootgly" rel="noopener noreferrer"&gt;Bootgly&lt;/a&gt;&lt;/strong&gt;, a base PHP framework, and its HTTP server runs as a long-running, event-driven process written in &lt;strong&gt;pure PHP&lt;/strong&gt; — no C extension, no Go sidecar, no third-party runtime in its core.&lt;/p&gt;

&lt;p&gt;On the TechEmpower &lt;code&gt;/plaintext&lt;/code&gt; route it peaks at &lt;strong&gt;1,076,709 requests per second&lt;/strong&gt;, ahead of Swoole, and roughly &lt;strong&gt;150× a Laravel + PHP-FPM&lt;/strong&gt; stack.&lt;/p&gt;

&lt;p&gt;This post is the result, how it actually works under the hood, the honest caveats, and a single &lt;code&gt;docker run&lt;/code&gt; you can paste to reproduce it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result first
&lt;/h2&gt;

&lt;p&gt;These are peak req/s per route, each server measured at its own best worker count. Methodology is at the bottom — and it's the same for every framework, which is the only way a benchmark like this means anything.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Route (req/s)&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Bootgly&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Swoole 6.2.0 (base)&lt;/th&gt;
&lt;th&gt;Hyperf&lt;/th&gt;
&lt;th&gt;ReactPHP&lt;/th&gt;
&lt;th&gt;AMPHP&lt;/th&gt;
&lt;th&gt;Laravel (Octane)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/plaintext&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,076,709&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;964,908&lt;/td&gt;
&lt;td&gt;358,576&lt;/td&gt;
&lt;td&gt;267,158&lt;/td&gt;
&lt;td&gt;99,093&lt;/td&gt;
&lt;td&gt;11,482&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,068,765&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;979,082&lt;/td&gt;
&lt;td&gt;347,233&lt;/td&gt;
&lt;td&gt;269,292&lt;/td&gt;
&lt;td&gt;99,244&lt;/td&gt;
&lt;td&gt;11,413&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;/db&lt;/code&gt; (single query)&lt;/td&gt;
&lt;td&gt;88,304&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;95,718&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;75,883&lt;/td&gt;
&lt;td&gt;43,190&lt;/td&gt;
&lt;td&gt;29,008&lt;/td&gt;
&lt;td&gt;8,094&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;/query&lt;/code&gt; (20×)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;20,341&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;17,263&lt;/td&gt;
&lt;td&gt;15,800&lt;/td&gt;
&lt;td&gt;924&lt;/td&gt;
&lt;td&gt;1,890&lt;/td&gt;
&lt;td&gt;2,326&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/fortunes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;73,640&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;98,557&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;75,650&lt;/td&gt;
&lt;td&gt;42,550&lt;/td&gt;
&lt;td&gt;14,954&lt;/td&gt;
&lt;td&gt;7,695&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;/updates&lt;/code&gt; (20×)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5,974&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3,721&lt;/td&gt;
&lt;td&gt;3,499&lt;/td&gt;
&lt;td&gt;1,086&lt;/td&gt;
&lt;td&gt;809&lt;/td&gt;
&lt;td&gt;321&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F95uisbeo1ew42ler2rk6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F95uisbeo1ew42ler2rk6.png" alt="Throughput vs server-workers — Bootgly vs Swoole (base mode) across the six TechEmpower routes" width="800" height="370"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;req/s as server-workers sweep from 1 → 24. Bootgly in blue, Swoole base mode in orange.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I'm not going to pretend Bootgly wins everything — but that single-number table actually &lt;em&gt;undersells&lt;/em&gt; what's going on, so here's the honest version. Those figures are each server at its &lt;strong&gt;own&lt;/strong&gt; best worker count; the curves above tell the real story. Across the full sweep, Bootgly leads Swoole on &lt;code&gt;/plaintext&lt;/code&gt;, &lt;code&gt;/json&lt;/code&gt;, &lt;code&gt;/query&lt;/code&gt; (+126%) and &lt;code&gt;/updates&lt;/code&gt; (+60%) at &lt;strong&gt;every&lt;/strong&gt; worker count. The two database-render routes are a scaling story: Bootgly is ahead for most of the range, and Swoole only overtakes near full saturation — the curves cross around 21 workers on &lt;code&gt;/db&lt;/code&gt; (Swoole ends just ~8% up at 24) and around 18 on &lt;code&gt;/fortunes&lt;/code&gt;, where Swoole's coroutine scheduler pulls clearly ahead at high worker counts. Against every &lt;em&gt;other&lt;/em&gt; framework in the table, Bootgly leads on every route, everywhere.&lt;/p&gt;

&lt;p&gt;The headline that matters to me isn't "beats Swoole." Swoole is excellent and battle-tested. The headline is that a server in the &lt;strong&gt;same throughput class as a C extension&lt;/strong&gt; is sitting here in plain PHP you can open and read.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you actually write
&lt;/h2&gt;

&lt;p&gt;Here is a complete HTTP server with a route and a 404 fallback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nf"&gt;Bootgly\WPI\Nodes\HTTP_Server_CLI&lt;/span&gt;&lt;span class="nc"&gt;\Request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nf"&gt;Bootgly\WPI\Nodes\HTTP_Server_CLI&lt;/span&gt;&lt;span class="nc"&gt;\Response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nf"&gt;Bootgly\WPI\Nodes\HTTP_Server_CLI&lt;/span&gt;&lt;span class="nc"&gt;\Router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt; &lt;span class="nv"&gt;$Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Router&lt;/span&gt; &lt;span class="nv"&gt;$Router&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Generator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$Router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt; &lt;span class="nv"&gt;$Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Hello World!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="c1"&gt;// Catch-all 404&lt;/span&gt;
   &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$Router&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt; &lt;span class="nv"&gt;$Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nv"&gt;$Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Not Found'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bootgly project Demo/HTTP_Server_CLI start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, an important clarification, because "a server in a dozen lines" would be a lie: &lt;strong&gt;that handful of lines is your application, not the server.&lt;/strong&gt; The server underneath it is a complete piece of software — HTTP/1.1 framing, a router with compile-time parameter constraints, a middleware pipeline, sessions, authentication and authorization, request validation, streaming multipart uploads, and an async PostgreSQL DBAL + ORM — all built in. What's small is the surface &lt;em&gt;you&lt;/em&gt; touch. What runs behind it is not small at all.&lt;/p&gt;

&lt;p&gt;That's the whole point of the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works under the hood
&lt;/h2&gt;

&lt;p&gt;The trick isn't a trick. It's just architecture that PHP has been able to support for years, assembled deliberately.&lt;/p&gt;

&lt;h3&gt;
  
  
  It's a long-running process, not FPM
&lt;/h3&gt;

&lt;p&gt;A normal PHP request lives and dies in milliseconds. Bootgly's server is a CLI process that boots &lt;strong&gt;once&lt;/strong&gt; and stays resident. There's no per-request bootstrap, no re-parsing, no re-wiring the container on every hit. Opcache + JIT then compile the hot paths and keep them compiled (that alone is worth ~50% on this workload). This is the same insight Swoole, RoadRunner, and Laravel Octane are built on — Bootgly just does it without leaving PHP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-process workers, via &lt;code&gt;pcntl&lt;/code&gt; and &lt;code&gt;posix&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;On boot, a master process forks &lt;strong&gt;N worker processes&lt;/strong&gt; with &lt;code&gt;pcntl_fork()&lt;/code&gt; and distributes accepted connections across them, so all your cores are actually used. Each worker is a real OS process with its own memory — a crash in one doesn't take down the others. The master handles UNIX signals properly (&lt;code&gt;SIGTERM&lt;/code&gt;, &lt;code&gt;SIGHUP&lt;/code&gt;, &lt;code&gt;SIGCHLD&lt;/code&gt;, &lt;code&gt;SIGUSR1&lt;/code&gt;…) for graceful shutdown and reloads, and can drop privileges to &lt;code&gt;www-data&lt;/code&gt; after binding a privileged port using &lt;code&gt;posix_setuid()&lt;/code&gt; / &lt;code&gt;posix_setgid()&lt;/code&gt;. In the benchmark above, the sweet spot was 24 workers on 24 logical CPUs.&lt;/p&gt;

&lt;h3&gt;
  
  
  An event loop made of &lt;code&gt;stream_select&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Inside each worker is a classic non-blocking event loop. The listen socket comes from &lt;code&gt;stream_socket_server()&lt;/code&gt;, every connection is flipped to non-blocking with &lt;code&gt;stream_set_blocking($socket, false)&lt;/code&gt;, and the worker waits on readiness with &lt;strong&gt;&lt;code&gt;stream_select()&lt;/code&gt;&lt;/strong&gt; — PHP's built-in &lt;code&gt;select()&lt;/code&gt; wrapper. No libuv, no &lt;code&gt;ext-event&lt;/code&gt;, no &lt;code&gt;ext-swoole&lt;/code&gt;. Sockets get tuned at the syscall level (&lt;code&gt;TCP_NODELAY&lt;/code&gt;, &lt;code&gt;SO_KEEPALIVE&lt;/code&gt;), and TLS is handled with &lt;code&gt;stream_socket_enable_crypto()&lt;/code&gt;. It is, genuinely, the kind of event loop you'd write in C — expressed in PHP's standard stream functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP is layered &lt;em&gt;on top of&lt;/em&gt; TCP
&lt;/h3&gt;

&lt;p&gt;This is the part I'm most fond of architecturally. Bootgly follows a strict layered design it calls I2P (Interface-to-Platform), and the HTTP server is quite literally a TCP server with HTTP bolted on through inheritance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HTTP_Server_CLI&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TCP_Server_CLI&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the request lifecycle is clean and one-directional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;raw bytes
   → TCP_Server_CLI        (accept, non-blocking read/write, backpressure)
   → HTTP decoders         (request-line + header framing, chunked, multipart)
   → Request               (typed, per-connection, no superglobals)
   → Router → middleware → your handler
   → Response → HTTP encoders
   → TCP_Server_CLI        (non-blocking, backpressure-aware write)
   → wire
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The TCP layer knows nothing about HTTP. The HTTP layer reuses every bit of the socket machinery below it. The same TCP foundation also powers a UDP server and the framework's HTTP/TCP/UDP &lt;em&gt;clients&lt;/em&gt; — write the hard part once, reuse it everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fibers for the work that would otherwise block
&lt;/h3&gt;

&lt;p&gt;An event loop only stays fast if nothing blocks it. The classic PHP problem is the database call: in a synchronous worker, one slow query freezes everything that worker is serving. Bootgly uses &lt;strong&gt;PHP 8.1 Fibers&lt;/strong&gt; to make that cooperative. A handler can defer work, and when it hits I/O — say, the native non-blocking PostgreSQL client talking to the connection pool — it &lt;em&gt;yields&lt;/em&gt; control back to the loop instead of stalling the worker. The loop serves other connections and resumes the fiber when the socket is ready. That's why &lt;code&gt;/query&lt;/code&gt; (20 sequential DB fetches) and &lt;code&gt;/updates&lt;/code&gt; come out ahead: the concurrency is real, not faked by a thread pool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero third-party dependencies
&lt;/h3&gt;

&lt;p&gt;Everything above uses &lt;strong&gt;only PHP's standard library&lt;/strong&gt; — &lt;code&gt;stream_*&lt;/code&gt;, &lt;code&gt;socket_*&lt;/code&gt;, &lt;code&gt;pcntl_*&lt;/code&gt;, &lt;code&gt;posix_*&lt;/code&gt;. There are no Composer packages in the framework core. The router, the decoders, the session handler, the test framework, the DBAL: all native. Your &lt;code&gt;vendor/&lt;/code&gt; directory for a Bootgly app's core is, effectively, empty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why pure PHP at all?
&lt;/h2&gt;

&lt;p&gt;"Just use Swoole" is a fair question, so here's the honest answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment.&lt;/strong&gt; A C extension means a compile step, a PECL install, a matching ABI, and a CI pipeline that has to carry it. Bootgly's server runs anywhere PHP 8.4 runs — &lt;code&gt;git clone&lt;/code&gt;, and go. No extension to build, nothing to keep in sync with your PHP minor version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supply chain.&lt;/strong&gt; No third-party runtime in the core means a dramatically smaller attack surface and nothing to audit but the framework itself. After the last few years of dependency-chain incidents across every ecosystem, "you can read the entire stack" is a feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding.&lt;/strong&gt; This is the personal one. My motto, stolen from Feynman, is &lt;em&gt;"What I cannot create, I do not understand."&lt;/em&gt; When the HTTP server, the TCP layer, the event loop, and the decoders are all PHP I wrote, there is no black box between my application and the socket. If something is slow or wrong, I can read straight down to the &lt;code&gt;stream_select()&lt;/code&gt; call. That's worth a lot when you're debugging production at 2 a.m.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest caveats
&lt;/h2&gt;

&lt;p&gt;If you take one thing from a benchmark post, take the caveats — they're how you tell whether to trust the numbers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bootgly is beta.&lt;/strong&gt; The 1.0 release is close, but the public API is still being finalized. Don't ship it to production yet; pin a version and expect changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PHP 8.4+, Linux.&lt;/strong&gt; It leans on modern PHP (Fibers, property hooks, asymmetric visibility) and is developed/tested on Debian-based Linux. Windows works under Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swoole wins the DB-render routes at saturation.&lt;/strong&gt; At peak worker counts Swoole takes &lt;code&gt;/db&lt;/code&gt; (barely — the curves cross around 21 workers) and &lt;code&gt;/fortunes&lt;/code&gt; (clearly, above ~18 workers). Below those, Bootgly leads both. A mature C coroutine scheduler earns the high-saturation crown.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/updates&lt;/code&gt; at extreme worker counts is not fully characterized.&lt;/strong&gt; Bootgly wins it at ≤~24–32 workers (the config above); at very high counts, concurrent batched &lt;code&gt;UPDATE&lt;/code&gt;s can deadlock in PostgreSQL itself. That high-concurrency behavior still needs validation on real many-core hardware before I'd call it settled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synthetic routes are synthetic.&lt;/strong&gt; TechEmpower routes are a fair &lt;em&gt;cross-framework&lt;/em&gt; comparison, not your app. Always benchmark your real workload.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reproduce it yourself
&lt;/h2&gt;

&lt;p&gt;This is the part that makes it real. Every cross-framework opponent ships as a &lt;strong&gt;self-contained Docker image&lt;/strong&gt; that bundles Bootgly + the opponent + PostgreSQL (which boots and seeds itself), so the whole benchmark is one command, zero host setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; bootgly/bootgly_benchmarks:swoole &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nb"&gt;test &lt;/span&gt;benchmark HTTP_Server_CLI &lt;span class="nt"&gt;--opponents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bootgly,swoole-base &lt;span class="nt"&gt;--loads&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;techempower:&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap the image tag for &lt;code&gt;workerman&lt;/code&gt;, &lt;code&gt;reactphp&lt;/code&gt;, &lt;code&gt;amphp&lt;/code&gt;, &lt;code&gt;roadrunner&lt;/code&gt;, &lt;code&gt;hyperf&lt;/code&gt;, or &lt;code&gt;laravel-octane&lt;/code&gt; to run any other opponent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Methodology:&lt;/strong&gt; 24 logical CPUs (WSL2 / Ryzen 9 3900X), PHP 8.4.22, 514 connections, 10 s per route, &lt;code&gt;DB_POOL_MAX=1&lt;/code&gt; for &lt;strong&gt;every&lt;/strong&gt; framework (identical per-worker DB footprint). Worker count was swept 1→24; figures are each framework's peak. Full comparison — features, performance, and the server's built-in security posture — lives on the &lt;a href="https://docs.bootgly.com/manual/WPI/HTTP/HTTP_Server_CLI/vs/" rel="noopener noreferrer"&gt;Bootgly vs Swoole, Hyperf, ReactPHP, AMPHP &amp;amp; Laravel&lt;/a&gt; page, and the raw runs are in &lt;a href="https://github.com/bootgly/bootgly_benchmarks/tree/main/HTTP_Server_CLI" rel="noopener noreferrer"&gt;&lt;code&gt;bootgly_benchmarks&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;Bootgly is heading toward a 1.0 with the API frozen and the docs filled out. The HTTP server, the async DBAL + ORM, sessions, auth, and the middleware stack are already in — the work now is stabilization, not new foundations.&lt;/p&gt;

&lt;p&gt;If a million requests per second in plain PHP is the kind of thing that makes you curious enough to read the source, the repo is here: &lt;strong&gt;&lt;a href="https://github.com/bootgly/bootgly" rel="noopener noreferrer"&gt;github.com/bootgly/bootgly&lt;/a&gt;&lt;/strong&gt;. A ⭐ helps more people find it, and I'm genuinely keen to hear where the design holds up and where it doesn't — especially from people who've shipped Swoole, RoadRunner, or Workerman in anger.&lt;/p&gt;

&lt;p&gt;What would you stress-test first?&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>performance</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
