Development Tips

PHP Async Patterns in 2026: Fibers, ReactPHP, Swoole, and When to Use Each

By Ken Key Feb 11, 2026 5 min read Updated Oct 16, 2026

PHP Async Patterns in 2026: Fibers, ReactPHP, Swoole, and When to Use Each
The short answer

Use native Fibers for lightweight concurrency inside existing code, ReactPHP when you want a mature event loop without extensions, and Swoole for high-throughput servers where you control the runtime. Only reach for async when profiling shows your time goes to I/O wait, not CPU.

Part of the complete web development guide.

On this page

Most PHP apps don’t need async. They need a faster database query or a cache. But there are real cases where concurrent I/O changes everything: hitting three APIs in one request, processing a queue, scraping, or anything that spends its life waiting on the network. Here’s how the options actually stack up in 2026, and where each one makes sense.

I’ve been writing PHP since the 5.x days, back when “async” meant shelling out to a queue worker and hoping for the best. The tooling has changed a lot. The decision-making hasn’t. You’re still trading complexity for throughput, and the trade only pays off when your bottleneck is I/O wait, not CPU.

First, know what you’re actually solving

Async helps when your code sits idle waiting on something external. A database call, an HTTP request, a file read. If your PHP process is burning CPU doing math or rendering templates, async will not help you. It’ll just make the code harder to read.

Run a quick profile before you reach for any of this. If a page takes 800ms and 700ms of that is three sequential API calls, you have an async problem. If it’s 700ms of image resizing, you have a scaling problem. Different fix.

Native Fibers (PHP 8.1+)

Fibers landed in PHP 8.1 and they’re the foundation everything else now builds on. A fiber is a pause-and-resume point in your code. It doesn’t do anything on its own. You still need an event loop or a scheduler to actually get concurrency. But it means libraries no longer have to fight the runtime with generators and promises wrapped in duct tape.

$fiber = new Fiber(function (): void {
 $user = Fiber::suspend('need user data');
 echo "Got: {$user}n";
});

$fiber->start();
// do something else here
$fiber->resume('Ken');

That’s the whole idea. Suspend, do other work, resume. In practice you rarely touch Fiber directly. You use a library that wraps it. Which brings us to the two big ones.

ReactPHP vs AMPHP vs Swoole

ReactPHP

The oldest of the group and still maintained. Non-blocking event loop, promise-based API, huge ecosystem of adapters for HTTP, MySQL, Redis, and so on. It runs on standard PHP-FPM or CLI, no extensions required.

use ReactHttpBrowser;
use ReactEventLoopLoop;

$client = new Browser();

$promises = [
 $client->get('https://api.example.com/a'),
 $client->get('https://api.example.com/b'),
 $client->get('https://api.example.com/c'),
];

ReactPromiseall($promises)->then(function (array $responses) {
 foreach ($responses as $response) {
 echo $response->getBody() . "n";
 }
});

Loop::run();

Three requests, roughly the time of the slowest one instead of the sum. That’s the win. The cost is that every library you pull in has to be async-aware. The moment you call a blocking file_get_contents() or a synchronous PDO query, you’ve stalled the whole loop.

AMPHP

AMPHP takes a different approach. Instead of promises, it uses fibers to make async code look synchronous. This is a big deal for readability. The same three requests:

use AmpHttpClientHttpClientBuilder;
use AmpHttpClientRequest;
use function Ampasync;
use function AmpFutureawait;

$client = HttpClientBuilder::buildDefault();

$futures = [
 async(fn () => $client->request(new Request('https://api.example.com/a'))),
 async(fn () => $client->request(new Request('https://api.example.com/b'))),
 async(fn () => $client->request(new Request('https://api.example.com/c'))),
];

$responses = await($futures);

No ->then() chains. It reads like regular PHP. Under the hood it’s still non-blocking, but the fiber suspension is hidden from you. For most teams in 2026 this is the easier sell if you’re starting fresh.

Swoole

Swoole is a PHP extension written in C. It gives you a coroutine runtime, plus its own HTTP server, WebSocket server, and task workers. It’s the fastest of the three by a wide margin because it keeps PHP resident in memory and skips the whole request-per-process model.

use SwooleCoroutine;
use SwooleCoroutineHttpClient;

Coroutinerun(function () {
 $clients = [];
 foreach (['a', 'b', 'c'] as $name) {
 $client = new Client('api.example.com', 443, true);
 $client->get("/{$name}");
 $clients[$name] = $client;
 }
 foreach ($clients as $name => $client) {
 echo "{$name}: " . strlen($client->body) . " bytesn";
 }
});

The catch: it’s an extension. Your host has to support it, your deploy has to build it, and your team has to understand that global state now persists between requests. That last part bites people. A static variable that reset every request under FPM will not reset under Swoole. I’ve watched that cause genuinely confusing bugs.

So which one?

  • Already on shared or managed hosting, need a small win: ReactPHP. No extension, works anywhere PHP runs.
  • Building a new async service, want readable code: AMPHP. Fibers make it feel normal.
  • Running your own infra, need maximum throughput: Swoole. Accept the operational cost.
  • Just need background jobs: none of the above. Use a queue.

That last point matters. A lot of “we need async PHP” conversations are really “we need a queue and a worker.” If a user doesn’t need the result right now, don’t make them wait. Push it to Redis or a database table, return immediately, process it out of band. That’s simpler than any of these libraries and it scales further.

The honest limits

Async PHP is not Node. You don’t get the same ecosystem. A lot of Composer packages still assume blocking I/O, and one blocking call inside a coroutine can freeze everything else on that worker. You also lose the isolation of the request-per-process model, which is a real safety net you’re giving up.

For most sites I work on, the answer is boring: cache the expensive thing, fix the slow query, add an index, and move on. Async is the right tool when you’ve measured the problem and it’s genuinely I/O-bound concurrency. Not before.

If you’re weighing this for a specific project, whether that’s a custom web development build or something you’re maintaining, the decision usually comes down to your hosting and your team’s comfort level more than raw benchmarks. Pick the one you can debug at 2am.

FAQ

Do I need async PHP for a normal website?

Almost never. A standard WordPress or Laravel site with decent caching will not benefit. Reach for async when you have measured, I/O-bound concurrency, like multiple external API calls per request.

Can I mix async libraries in one project?

You can, but don’t. ReactPHP and AMPHP each run their own event loop, and nesting them causes deadlocks that are miserable to trace. Pick one and stay with it.

Is Swoole worth the setup cost?

Only if you control your servers and need the throughput. For most teams the operational overhead and the persistent-state gotchas outweigh the speed gain over AMPHP or ReactPHP.

Have a project like this?

I do custom web development for Long Island businesses. If you need this done right, let’s talk.