Most PHP code runs one step at a time: it asks the database, waits, calls an API, waits, then answers the visitor. Asynchronous programming lets a PHP program start several slow tasks and handle them as they finish, instead of waiting for each in turn. This guide explains what async PHP is in 2026, the main tools (Fibers, Amp, ReactPHP, Swoole and Guzzle promises) with working examples, and where each one can run.
Async PHP helps when your code spends most of its time waiting on the network, for example calling several APIs at once or running a websocket or chat server. Since PHP 8.1, Fibers give PHP a built-in way to pause and resume code, and libraries such as Amp and ReactPHP build on an event loop to run many waits at the same time. Long-running async servers need a server where you control processes and ports, such as a VPS; ordinary shared hosting runs PHP per request and stops long-running processes.
1. Synchronous and asynchronous, in plain terms
In synchronous code, each line finishes before the next starts. If you call three APIs that take one second each, the page takes about three seconds.
In asynchronous code, you start all three calls and wait once while they are in flight, so the page takes about one second.
Async does not make PHP compute faster. It only removes idle waiting. It helps with I/O-bound work (network calls, sockets, slow services) and does nothing for CPU-bound work such as resizing images or heavy calculations. For CPU work you need more processes or a job queue, not async.
2. How PHP normally runs, and why that matters
On a typical web server, PHP runs through PHP-FPM or CGI: a request comes in, a PHP process runs your script from the top, sends the response and forgets everything. Each request is short-lived.
Async PHP usually works differently. Libraries like ReactPHP, Amp and Swoole run an event loop: one long-running PHP process that keeps many connections open and reacts to events as they happen. That model is powerful, but it needs somewhere a PHP process can stay alive and, for servers, listen on its own port.
| Approach | Runs inside a normal web request? | Needs a long-running process? |
|---|---|---|
| Fibers (built into PHP 8.1+) | Yes | No |
| Amp or ReactPHP for concurrent HTTP calls within one request | Yes | No |
| Guzzle promises for concurrent requests | Yes | No |
| ReactPHP or Amp HTTP or websocket server | No | Yes |
| Swoole or OpenSwoole server | No | Yes, plus a PHP extension |
3. Fibers: the building block in PHP 8.1 and later
A Fiber is a block of code that can pause itself and be resumed later, keeping its state. You rarely use Fibers directly; libraries such as Amp v3 and recent ReactPHP components use them so that async code reads like normal code.
<?php
$fiber = new Fiber(function (string $task): string {
echo "Starting $task\n";
$reply = Fiber::suspend('waiting'); // pause here
return "$task finished with $reply";
});
$status = $fiber->start('download'); // runs until suspend()
echo "Fiber says: $status\n"; // "waiting"
$fiber->resume('200 OK'); // continue from suspend()
echo $fiber->getReturn(), "\n"; // "download finished with 200 OK"On its own this is not concurrent. An event loop is what decides which paused Fiber to resume when its data arrives.
Before Fibers, libraries used generators (yield) for the same job. You will still see generator-based coroutines in older code; new code should use a Fiber-based library.
4. Amp: async code that reads like normal code
Amp version 3 is built on Fibers and the Revolt event loop. async() starts a task and returns a Future; await() waits for the results.
composer require amphp/amp<?php
require __DIR__ . '/vendor/autoload.php';
use function Amp\async;
use function Amp\delay;
use function Amp\Future\await;
$started = microtime(true);
$a = async(function () { delay(1); return 'A done'; });
$b = async(function () { delay(1); return 'B done'; });
[$resultA, $resultB] = await([$a, $b]);
printf("%s, %s in %.1f s\n", $resultA, $resultB, microtime(true) - $started);
// about 1.0 s, not 2.0 sdelay() stands in for real waiting, such as an HTTP request with amphp/http-client or a database query with amphp/mysql. The key point: both tasks wait at the same time.
5. ReactPHP: an event loop and non-blocking servers
ReactPHP is a set of low-level components: an event loop, streams, sockets, DNS, an HTTP client and an HTTP server. Current versions start the loop automatically, so you no longer create and run it by hand as older tutorials show.
composer require react/http<?php
require __DIR__ . '/vendor/autoload.php';
use Psr\Http\Message\ServerRequestInterface;
use React\Http\HttpServer;
use React\Http\Message\Response;
use React\Socket\SocketServer;
$http = new HttpServer(function (ServerRequestInterface $request) {
return Response::plaintext("Hello World\n");
});
$socket = new SocketServer('127.0.0.1:8080');
$http->listen($socket);
echo "Listening on http://127.0.0.1:8080\n";Run it with php server.php and it keeps running, serving many connections from one process. In production you put it behind a reverse proxy such as Nginx or Caddy and keep it alive with a process manager such as systemd or Supervisor.
6. Swoole and OpenSwoole: a PHP extension for servers
Swoole (and its community fork OpenSwoole) is a PHP extension written in C, installed with PECL or your distribution's packages. It adds coroutines and fast built-in HTTP, WebSocket and TCP servers.
<?php
$server = new Swoole\Http\Server('127.0.0.1', 9501);
$server->on('request', function ($request, $response) {
$response->header('Content-Type', 'text/plain');
$response->end("Hello World\n");
});
$server->start();Because it is an extension, you need control of the PHP installation. Frameworks also use it: Laravel Octane can run on Swoole, RoadRunner or FrankenPHP to keep your app in memory between requests.
7. Guzzle promises: concurrent HTTP calls
If you only need to call several APIs at once inside a normal page, you do not need a server at all. Guzzle's async methods return promises, and Utils::settle() waits for all of them.
<?php
require __DIR__ . '/vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Promise\Utils;
$client = new Client(['timeout' => 10]);
$promises = [
'rates' => $client->getAsync('https://api.example.com/rates'),
'weather' => $client->getAsync('https://api.example.com/weather'),
];
foreach (Utils::settle($promises)->wait() as $name => $result) {
echo $name, ': ', $result['state'] === 'fulfilled'
? $result['value']->getStatusCode()
: $result['reason']->getMessage(), "\n";
}Note the ->wait(). A common mistake in older examples is to call getAsync() and then() without ever waiting, so the script ends before the requests run. Guzzle runs requests in parallel only when PHP's curl_multi_* functions are available; without them it still works, but one request at a time.
8. Pros, cons and when to use async
- Calling several slow APIs or services at once
- Websockets, chat, live dashboards and long-lived connections
- High-concurrency services where most time is spent waiting
- Keeping an app in memory between requests for speed
- Harder to debug: code no longer runs top to bottom
- One blocking call (a plain
sleep(), a blocking database driver) can stall every task in the loop - Memory leaks matter in long-running processes, which are never "reset" between requests
- Needs a server where you control processes, ports and PHP extensions
For most websites (a company site, WordPress, a shop, a normal Laravel app) classic PHP with caching is simpler and fast enough. Reach for async when you have a clear waiting problem, not by default.
9. Running async PHP on Domain India
On Domain India shared hosting (cPanel, DirectAdmin, Webuzo), PHP runs per request. Long-running processes are stopped, you cannot open your own listening port, and functions such as proc_open are disabled, so Composer cannot run on the server. See PHP disabled functions on shared hosting.
What that means in practice:
- Shared hosting: Fibers work on PHP 8.1 or later, which you can select in your control panel. Libraries such as Amp or Guzzle can be used inside a single request if you install them on your computer and upload the project with
vendor/.curl_multi_execis disabled on our cPanel servers and on most DirectAdmin sites, so do not expect concurrent HTTP calls to run in parallel there. ReactPHP, Amp or Swoole servers will not run. - App Platform: runs your app as a long-lived container. Only Node.js is detected automatically; for a PHP event-loop server, include a Dockerfile. Read getting started with the App Platform.
- VPS: self-managed with full root access, so you can install Swoole, run ReactPHP or Amp servers under systemd or Supervisor, and put Nginx or Caddy in front.
- 512 MB RAM per app
- 1 vCPU
- 5 GB NVMe SSD
- PostgreSQL Database
- 1 vCPU
- 2 GB DDR4 RAM
- 64 GB NVMe SSD Storage
- 2 TB Monthly Bandwidth
Plan cards show Domain India list prices, excluding 18% GST.
Frequently asked questions
Does PHP support asynchronous programming?
Yes, through libraries and extensions. PHP 8.1 added Fibers, which let code pause and resume, and libraries such as Amp and ReactPHP use an event loop to run many network waits at the same time. Swoole and OpenSwoole add async servers as a PHP extension.
Will async PHP make my website faster?
Only if your code spends its time waiting, for example calling several APIs one after another. Async removes that waiting. It does not speed up CPU-heavy work, and for a normal website caching usually helps more.
What is the difference between ReactPHP, Amp and Swoole?
ReactPHP is a set of low-level event-loop components written in PHP. Amp is a Fiber-based library that lets async code read like normal code. Swoole is a C extension with its own coroutine engine and built-in servers, so it needs control of the PHP installation.
Can I run ReactPHP or Swoole on shared hosting?
No. Their servers must run as long-lived processes listening on their own port. Shared hosting runs PHP per request, stops long-running processes and does not let you open ports. Use an App Platform container with a Dockerfile, or a VPS.
Why does my Guzzle getAsync request never run?
Promises must be waited on. Call wait() on the promise, or collect several promises and call Utils::settle($promises)->wait(), otherwise the script can end before the requests are sent.
Ready to build? For a PHP event-loop server, start with the App Platform and a Dockerfile, or choose a self-managed VPS for full control. If your app is a normal PHP site, cPanel hosting runs it per request without any of this setup.
Full root access to install Swoole, run ReactPHP or Amp servers and manage your own processes.
See VPS plans