Laravel 11, the latest major release of the popular PHP framework, introduces some exciting improvements that make building robust, scalable web applications faster and easier. In this post, we’ll explore some of the most noteworthy new features, changes, comparison of the pros and cons of different kinds of implementations and approaches and examples.
The Application Bootstrap File
One of the biggest changes in Laravel 11 is the revamping of the bootstrap/app.php file. This file now serves as the main entry point and configuration file for your application. Instead of configuring routing, services, and more in separate files, you can now do it all in app.php.
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: DIR.'/../routes/web.php',
commands: DIR.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
This provides a code-first way to configure your application’s core behavior in a single location. Some key things you can now configure in app.php include:
- Routing — Easily define your route files for web, CLI, and health check endpoints.
- Middleware — Customize middleware behavior and pipeline order.
- Service Providers — Manually register providers if needed.
- Error Handling — Configure custom exception and error handling.
Overall, this new structure makes it faster to configure and bootstrap a new Laravel app.
Streamlined Service Providers
In previous versions of Laravel, new applications included several default service providers out of the box for authentication, validation, routing, and more.
Laravel 11 takes a more minimal approach. Now there is only a single AppServiceProvider by default. The responsibilities of the other providers have been moved into the framework itself or can be handled in your AppServiceProvider if needed.
For example, you can manually register event listeners, route model bindings, policies, and gates directly in AppServiceProvider now. This reduces clutter and allows you to only add what you actually need for your application.
public function register()
{
$this->app->singleton(UserRepository::class, function () {
//
});
}
public function boot()
{
// Register Auth Gates
Gate::define('update-post', [PostPolicy::class, 'update']);
// Register Model Bindings
Route::model('user', User::class);
}
This streamlined service provider structure simplifies bootstrapping a new app and helps avoid unnecessary bloat.
Opt-In APIs and Broadcasting
The api.php and channels.php routes files are no longer included by default. Since many apps don’t need API or websocket/broadcasting routes, these are now optional.
You can easily add them when needed using Artisan commands:
php artisan install:api
php artisan install:broadcasting
This allows you to start with a leaner application structure and opt-in to more advanced routing as your app evolves.
Unified Middleware Handling
In previous Laravel releases, the HTTP kernel app/Http/Kernel.php class handled configuring the global middleware pipeline. This added some complexity when trying to customize middleware order and behavior.
In Laravel 11, the kernel has been removed in favor of configuring middleware directly in bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
EncryptCookies::class,
]);
$middleware->api(except: [
'/health',
]);
})
You can now easily customize middleware behavior and pipeline for your web and API routes. Common tasks like excluding middleware for certain routes or appending additional middleware is much simpler without a dedicated kernel class.
Improved Logging
Logging has been improved in Laravel 11 with a new LogManager class that provides a simple interface for configuring logs and writing log messages:
LogManager::configure(basePath('storage/logs'));
LogManager::info('User logged in');
The new LogNotifier class allows you to easily register handlers to send log messages to external services like Bugsnag or Sentry:
LogNotifier::add(
new SentryHandler(Client::make())
);
Logging can also be configured based on environment variables, allowing different logging behavior between dev/prod:
LogManager::configureBasedOnEnvironmentVars();
Overall, Laravel 11 provides a simpler log configuration syntax with improved extensibility.
Ability to Delay Job Execution
The job batching and scheduling capabilities of Laravel’s queues have been improved. Now you can easily delay a job’s execution until a later time using the delay
method on a job instance:
ProcessPodcast::dispatch()
->delay(now()->addMinutes(10));
This provides an easy way to handle scheduled tasks and workflows directly within your job classes.
Custom PHPunit Assertions
PHPUnit assertions allow you to express the expected behavior of your application in a clear, concise way. Laravel 11 makes it easy to define your own custom assertions using the new assert
helper:
assert('emails.sent', $expectedCount, $actualCount);
Custom assertions improve test readability by allowing you to describe the expected behavior in your application’s domain language.
Console Testing Improvements
Testing Artisan console commands is easier thanks to improved assertion syntax in Laravel 11:
public function test_new_user_command()
{
$this->artisan('user:new')
->expectsOutput('New user created successfully')
->assertExitCode(0);
}
The new expectsOutput
and assertExitCode
assertions allow you to easily validate exit codes and output of console commands.
Closure Dispatch Binding
When dispatching jobs in Laravel, it’s common to pass currently authenticated user information or other data along with the job. Normally this involves injecting a class into the job’s constructor.
Now in Laravel 11, you can use closure dispatch binding to share state with a job without modifying its constructor:
use App\Jobs\ProcessPodcast;
use Illuminate\Support\Facades\Auth;
dispatch(function () {
return new ProcessPodcast(...);
})->bind(Auth::user());
This provides a cleaner way to inject runtime data into a job instance before dispatching.
Lazy Collections
Lazy collections allow you to work with extremely large datasets without loading the entire collection into memory at once. Now in Laravel 11, the lazy()
method converts a standard collection to a lazy one:
$users = User::all()->lazy();
$paidUsers = $users->filter(fn ($user) => $user->plan === 'paid');
The results are loaded lazily, processing small batches at a time. This enables working with gigantic datasets efficiently.
Improved Rate Limiting
Laravel’s built-in rate limiter is even more powerful in Laravel 11. You can now limit based on dynamic data like route parameters:
RateLimiter::for('uploads', function ($pipe) use ($user) {
return $pipe->perMinute(5)->by($user->id);
});
You can also limit based on arbitrary values besides IPs by passing a Closure
:
RateLimiter::for('login', function ($pipe) {
return $pipe->perMinute(10)->by(fn() => $this->auth->user()->id);
});
These improvements allow very customized rate limiting behaviors.
Multiple Mail Drivers
In previous releases, Laravel applications could only have a single configured mail driver. Now in Laravel 11, you can configure and use multiple mail drivers at once:
'mailers' => [
'smtp' => [
'transport' => 'smtp'
],
'postmark' => [
'transport' => 'postmark'
],
],
Then specify which to use per mailable class:
namespace App\Mail;
use Illuminate\Mail\Mailable;class OrderShipped extends Mailable
{
public $mailer = 'postmark';
}
Support for multiple mailers makes it easy to use different services for transactional vs. marketing email.
Pros and Cons
Here is a comparison of the pros and cons of different kinds of implementations and approaches for the new Laravel 11 features:
The Application Bootstrap File
Pros of the New App.php Approach:
- More centralized configuration in one place
- Cleaner code structure without separate kernel files
- Easier to see all configuration at a glance
Cons of the New App.php Approach:
- Potential for app.php file to grow very large
- More difficult to understand for those used to old structure
- Harder to modify middleware order since it’s in PHP instead of kernel file
Pros of the Old Kernel Approach:
- Separates concerns into dedicated classes
- Allows modifying middleware order without touching code
- Familiar structure for experienced Laravel developers
Cons of the Old Kernel Approach:
- Configuration spread across several files
- More files to manage and scroll through
Service Providers
Pros of Streamlined Providers:
- Less bloat in new app skeleton
- Forced to be more purposeful about what you register
- Easier to understand provider responsibilities
Cons of Streamlined Providers:
- Must manually register common functionality now
- More decisions required early in app building
- Potential for misconfiguring or missing key providers
Pros of Old Providers:
- Registration of most common needs handled automatically
- Conventions for organizing code established
- New apps work “out of the box” with reasonable defaults
Cons of Old Providers:
- Lots of unused providers in most apps
- Harder to find where services are registered
- New developers rely on defaults instead of learning
Opt-In Routing
Pros of Opt-In Routing:
- No unnecessary route files cluttering structure
- Start with lean base and opt-in later
- Clearer separation between API and web features
Cons of Opt-In Routing:
- Easy to forget to add API/broadcasting later if needed
- Multiple commands required to replicate old structure
- Can’t rely only on default scaffolding
Pros of Default Routing Files:
- Works out of the box for common use cases
- Clear conventions for organizing routes
- New apps have reasonable starting structure
Cons of Default Routing Files:
- Many apps don’t need default API and broadcasting
- Creates clutter in simple applications
- Harder to understand intended separation of concerns
So in summary, while the new Laravel 11 conventions provide cleaner and more flexible code, they do require more thoughtful configuration for common needs up front. The old approaches had more prescriptive defaults that allowed for faster building at the expense of potential bloat. But overall, both offer reasonable ways to structure Laravel applications.
Example
Here a example of the steps to configure and send email using multiple mail drivers in Laravel 11:
1. Install and configure mail driver packages
Use Composer to install packages for the mail services you want to use, like guzzlehttp/guzzle
for Mailgun or wildbit/swiftmailer-postmark
for Postmark.
2. Define mail driver connections
In config/mail.php
, specify your connections under the mailers
config. For example:
'mailers' => [
'smtp' => [
'transport' => 'smtp',
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
'port' => env('MAIL_PORT', 587),
// ...
],
'postmark' => [
'transport' => 'postmark',
'token' => env('POSTMARK_TOKEN'),
],
],
3. Create your mailable classes
Generate mailable classes as normal with make:mail
. Be sure to specify which mailer each one should use:
public $mailer = 'postmark';
4. Queue and send the mailables
Queue the mailables as needed in your app logic, using your preferred queue driver:
NotificationMailer::dispatch($user);
ReminderMailer::dispatch($customer)->delay(now()->addMinutes(30));
5. Configure mail defaults
If desired, set default mailers in config/mail.php
:
'defaults' => [
'mailer' => 'smtp',
'from' => [email protected]',
],
],
6. Send mail
Use the Mail
facade to send mail. It will use the configured mailer and defaults:
Mail::to($user)->send(new OrderConfirmation($order));
That covers the main steps to start sending mail through multiple drivers in Laravel 11! The key is defining connections, assigning per mailable class, queuing, and using the Mail facade.
Conclusion
Laravel 11 contains many smaller improvements as well, like:
- Model factory classes
Illuminate/Testing
namespace- Custom Blade compiler extensibility
- Improved
event:list
Artisan command
Overall, the improvements in Laravel 11 help you build robust, enterprise-grade applications faster and with cleaner code. The upgrades to logging, rate limiting, queues, mail, and testing demonstrate Laravel’s continued evolution as a mature framework.
So give Laravel 11 a try today on your next project! The intuitive API and developer experience make it a joy to use for building modern web applications.