PHP Async in 2026: Fibers, Coroutines and the Road to Native Async
Direct answer: PHP can do async today, just not with built-in async/await syntax. Fibers (PHP 8.1) give the language pausable functions. ReactPHP and AMPHP build event loops on top of them in pure PHP, and Swoole provides coroutines through an extension. PHP 8.6 adds a native polling API (Io\Poll), and an RFC for engine-level concurrency is under discussion. For real-time apps, PHP is viable now. It just takes more deliberate choices than Node.js.
"PHP can't do async" is one of the most common reasons teams pick Node.js over PHP. It's half true. This post explains what exists today, what's coming, and how to decide. It's part of my PHP in 2026 series.
Why async is harder in PHP than in Node.js#
Node.js was built around one event loop from day one, so every database driver and HTTP client is non-blocking by default. PHP was built around one request per process. Its standard functions (file_get_contents(), PDO, sleep()) block, and decades of libraries assume they can.
So PHP async isn't only a syntax problem. Every I/O call has to cooperate with a scheduler, or it blocks everything else running in that process.
Fibers: the foundation (PHP 8.1)#
A fiber is a function that can pause itself and be resumed later, keeping its full call stack. Fibers aren't parallelism, and they don't do I/O by themselves. They're a building block that lets libraries write async code that looks synchronous:
$fiber = new Fiber(function (): string {
$value = Fiber::suspend('waiting'); // pause here
return "resumed with {$value}";
});
$status = $fiber->start(); // "waiting"
$fiber->resume('data'); // continues after suspend()
Application code rarely touches fibers directly. Their value is that libraries no longer need promise chains or generators everywhere.
The options today#
| Option | How it works | Best for | Trade-off |
|---|---|---|---|
| ReactPHP | Pure-PHP event loop with promises. Long-established and widely used. | Socket servers, workers, concurrent HTTP calls | Needs ReactPHP-compatible libraries for I/O |
| AMPHP (v3) | Pure-PHP event loop built on fibers, so code reads like normal synchronous PHP | Concurrent clients and servers without a C extension | Same ecosystem constraint: blocking libraries still block |
| Swoole | C/C++ extension with coroutines and runtime hooks that make many standard functions non-blocking | High-concurrency HTTP and WebSocket servers, parallel I/O in a request, Laravel Octane | An extension to install and maintain, plus long-running-worker discipline |
| Queues and workers | Push slow work to background jobs (Laravel Horizon, Symfony Messenger) | Emails, exports, webhooks, anything users don't wait on | Not real-time, but solves most "we need async" problems |
The honest truth: most teams asking for async actually need queues. If the user doesn't wait for the result, put it in a job. Reach for an event loop when one request or connection genuinely needs to do several I/O operations at once, or hold thousands of connections open.
Concurrency inside a request#
With Laravel Octane on Swoole, independent lookups run in parallel instead of one after another:
[$user, $orders, $notifications] = Octane::concurrently([
fn () => User::find($id),
fn () => Order::recentFor($id),
fn () => Notification::unreadCount($id),
]);
Three 20 ms queries take about 20 ms instead of 60 ms. We use this pattern on dashboards; the full setup is in how we use Octane + Swoole, and the runtime trade-offs are in PHP runtimes explained.
What's coming: native async in the engine#
- PHP 8.6:
Io\Poll. A native polling API over epoll, kqueue and friends. Event loops can stop relying onstream_select(), which scales poorly. It's a quiet but important foundation. See PHP 8.6 features. - RFC: Concurrency Support in the PHP Engine (under discussion). Extracted from the larger TrueAsync project, it proposes an engine-level coroutine core with a pluggable scheduler. With no scheduler loaded, PHP behaves exactly as it does today. It adds no new syntax; it's the plumbing that would let a standard async model exist across extensions.
- No
async/awaitkeywords are on the table yet. If engine-level concurrency lands, syntax and standard-library integration would come in later RFCs.
My read: native async is a multi-release journey, not something to wait for. The tools that exist today are production-ready.
PHP vs Node.js for real-time work#
| Need | PHP option | Node.js |
|---|---|---|
| Background jobs | Excellent (Horizon, Messenger) | Good (BullMQ etc.) |
| WebSockets for app notifications | Good: Laravel Reverb, Swoole | Excellent |
| Parallel I/O in a request | Good with Swoole/Octane or AMPHP | Native |
| Thousands of long-lived connections | Possible with Swoole or ReactPHP | Native strength |
| Collaborative editors, streaming-heavy apps | Workable, but against the grain | Usually the better fit |
That matches what we concluded in why we chose Laravel over Node.js: PHP for the product, and a dedicated real-time service where the product is mostly real-time.
Key takeaways#
- PHP has no
async/await, but fibers (8.1), ReactPHP, AMPHP and Swoole make async PHP production-ready today. - Most "we need async" problems are solved by queues. Use event loops when a request truly needs concurrent I/O.
- PHP 8.6's
Io\Polland the engine-concurrency RFC are building the foundation for native async. - For heavily real-time products, Node.js is still the more natural fit. For most products, PHP plus a queue plus WebSockets is enough.