Skip to main content

What is concurrency

If you execute multiple independent operations—such as requests to several external APIs or database aggregations—sequentially, the total time is the sum of each operation. If you execute them concurrently, the total time is reduced to about the time of the single slowest operation. Laravel’s Concurrency facade provides a simple API for exactly this kind of concurrent execution.
The Concurrency facade was introduced in Laravel 11 and continues to be available in Laravel 13. The default driver uses child PHP processes, so it works without any additional packages.

How it works

The Concurrency facade serializes the closures you pass in, sends them to a hidden Artisan command, and runs each one as a separate PHP process. When each operation completes, the return value is serialized back to the parent process. Three drivers are available.

Basic usage

Concurrency::run()

If you pass an array of closures to the run() method, they are executed concurrently. The return value is an array of each closure’s return values.
You can destructure the array to assign each result to a variable. The order of the return values matches the order of the closures.

Specifying a driver

To use a specific driver, use the driver() method.
To change the default driver, publish the configuration file and update the default option.

Using the fork driver

The fork driver is faster than the process driver, but it only works in a PHP CLI environment (Artisan commands or queue workers). It cannot be used during a web request. Before using it, install the spatie/fork package.
The fork driver does not work during web requests. Use it when running concurrency inside Artisan commands or queue workers.

Not caring about the return value: Concurrency::defer()

If you aren’t interested in the results and want the operation to run in the background after the HTTP response has been returned, use the defer() method.
The closures are not executed at the moment you call defer(). They run concurrently after the HTTP response has been sent to the user.
defer() is a great fit for operations you don’t want to make the user wait for, such as recording analytics data or warming up caches.

Practical example: calling multiple external APIs concurrently

Consider a dashboard for an e-commerce site that fetches information from three APIs: inventory management, sales aggregation, and shipping status.

Sequential execution (before)

Concurrent execution (after)

If each API takes 1 second, sequential execution takes 3 seconds in total, while concurrent execution completes in about 1 second.

Running multiple database aggregations concurrently

When using the process driver for database aggregations, each child process opens a new database connection. When you run many operations concurrently, watch out for your database’s maximum connection limit.

Configuration for testing

In your test environment, using the sync driver runs closures sequentially. There is no process-startup overhead from concurrency, so tests run faster.
Alternatively, you can change the default driver in .env.testing.

Caveats

Closures are serialized and passed to child processes. You cannot capture unserializable objects (such as database connections, file handles, or resources) from the enclosing scope. Recreate the objects you need inside the closure.
The process driver has a child-process startup cost, so for very short operations (a few milliseconds or less), concurrent execution may not be faster. It shines when parallelizing operations that take at least 100ms, such as HTTP requests or database aggregations.
The fork driver forks the PHP process, so it cannot be used during web requests (FPM or Apache). Only use it inside Artisan commands or queue workers.
If an exception occurs during concurrent execution, run() re-throws the exception. If you want the other operations to continue when an individual operation raises, use try/catch inside the closure.

Next steps

Queues and jobs

Learn how to run operations asynchronously in the background with queues and jobs.
Last modified on July 13, 2026