
We attended Laracon US 2024 in Dallas, where Taylor Otwell and the Laravel core team announced a wave of open-source additions to the framework. The features below - defer(), Cache::flexible, the Concurrency facade, and more - shipped in Laravel 11 point releases during 2024, and they addressed real gaps we kept running into on client projects.
A note on currency, since Laravel moves fast: everything covered here remains standard in Laravel 12 and Laravel 13, the current release. Nothing below has been removed or deprecated - these are now simply part of how modern Laravel applications get built. Here's what each one does and why it earned its place.
New Defer Function
Ever wished your application could respond faster? The new defer() function lets you postpone certain tasks until after the user receives the response. This keeps your app feeling lightning-quick!
How It Works
You can use defer() to delay functions that don't need to run immediately. For example, reporting metrics or sending emails.
use App\Services\Metrics;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use function Illuminate\Support\defer;
Route::post('/orders', function (Request $request) {
// Process the order...
$order = Order::create($request->all());
// Defer the metrics reporting
defer(fn () => Metrics::reportOrder($order));
return response()->json($order);
});
In this example, the user gets their order confirmation without waiting for the metrics to be reported. Neat, right?
Smarter Caching 🧠
Caching can be tricky, especially when cached data expires, and users experience delays. The new Cache::flexible method introduces a smart solution by serving cached data while refreshing it in the background.
How It Works
The flexible method accepts an array with two values:
-
Fresh period: How long the cache is considered fresh.
-
Stale period: How long stale data can be served.
$value = Cache::flexible('users', [300, 600], function () {
return DB::table('users')->get();
});
-
For the first 5 minutes (300 seconds), the data is fresh.
-
Between 5 and 10 minutes, stale data is served, and the cache refreshes in the background.
-
After 10 minutes, new data is fetched immediately.
This keeps your app responsive while ensuring data is up-to-date.
New Concurrency Facade ⏱️
Need to run multiple tasks at the same time? The new Concurrency facade lets you execute closures concurrently, boosting your app's performance. It's like having multiple hands to get the job done
Running Concurrent Tasks
Here's how you can run tasks concurrently:
use Illuminate\Support\Facades\Concurrency;
use Illuminate\Support\Facades\DB;
[$userCount, $orderCount] = Concurrency::run([
fn () => DB::table('users')->count(),
fn () => DB::table('orders')->count(),
]);
Both tasks run simultaneously, reducing the total execution time.
Deferring Concurrent Tasks
You can also defer concurrent tasks to run after the response is sent:
use App\Services\Metrics;
use Illuminate\Support\Facades\Concurrency;
Concurrency::defer([
fn () => Metrics::report('users'),
fn () => Metrics::report('orders'),
]);
This is perfect for tasks that don't need to complete before the user gets a response.
Temporary URLs with Local Filesystem
Good news! You can now generate temporary, signed URLs for files stored locally. This is great for securely sharing files without exposing their actual paths.
Enabling Temporary URLs
First, ensure your local disk supports serving files:
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'serve' => true,
],
Generating a Temporary URL
use Illuminate\Support\Facades\Storage;
$url = Storage::temporaryUrl(
'invoices/receipt.pdf', now()->addMinutes(15)
);
Blade's New "when" Helper
Writing conditional attributes in Blade just got easier! The when helper simplifies your templates by conditionally adding attributes.
How It Works
Instead of writing long conditional statements, you can do this:
<div {{ when($isActive, 'class=”active”') }}>
<!-- Content here -->
</div>
If $isActive is true, the class="active" attribute is added. Otherwise, it's skipped. Simple and clean!
FirstOrFail in Query Builder
The query builder now has a firstOrFail method, similar to Eloquent's. This means you can fetch the first record or throw an exception if none is found.
$user = DB::table('users')->where('email', $email)->firstOrFail();
No more checking for null values—handle exceptions as needed.
Skip Middleware for Queued Jobs
Need to skip a queued job based on certain conditions? The new Skip middleware lets you do just that without cluttering your handle method.
How It Works
Add the Skip middleware to your job:
use Illuminate\Queue\Middleware\Skip;
public function middleware()
{
return [
Skip::when($this->shouldSkip()),
];
}
protected function shouldSkip()
{
// Your condition here
return $this->attempts() > 3;
}
If shouldSkip() returns true, the job is skipped.
A Cleaner Way to Log 🧼
Logging is super important, but let’s be honest, the global info() method can feel a little... That’s why Laravel 11 gives you a namespaced log function to keep your logging tidy and organized! 🙌
Example:
Now you can log with style by using the log() function in your custom namespace:
use function Illuminate\Log\log;
log('User has been successfully created.');
Wrapping Up
These features arrived with Laravel 11 and remain standard in Laravel 12 and 13, so they're safe to build on regardless of which supported version you're running. If you're still on Laravel 11 or older, note that Laravel 11 reached end-of-security support in March 2026 - our Laravel 11 breakdown covers the version itself, and upgrading to a supported release is worth prioritizing.
While we are at it, we also specialize in Laravel development, so if you’d like to learn more about what we can offer and what Laravel development services we can provide, feel free to check out our dedicated page - we’re here and ready to chat.








.webp&w=1920&q=75&dpl=dpl_BRe7iXcVH4XjhJwZSen2jWtGWenx)