# Laravel 11's New Slim Skeleton Structure

> A look at Laravel 11's leaner skeleton, the defaults that were removed, and the concrete impact on everyday development workflows.

- Published: 2024-03-03
- Category: Framework & Library
- Tags: Laravel
- Reading time: 3 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/laravel-11-slim-skeleton-structure/
- Language: en-US
- Author: Muhammet Şafak

---
Laravel 11 shipped in March 2024, and its most noticeable change wasn't a technical feature: the skeleton structure was significantly trimmed down. My initial reaction — and I suspect this was shared by many Laravel developers — was a mild sense of disorientation. File locations and registration points that had become muscle memory over years had moved.

After a few days of working with it, though, I realized this wasn't a superficial reorganization. It was a deliberate principle: "you shouldn't ship what you don't use."

## What was removed, what was simplified

In [Laravel 10](/en/blog/laravel-10-stricter-types-and-the-process-layer/) and earlier, `app/Http/Kernel.php` was the central registration point for the [middleware stack](/en/blog/adding-shared-behavior-to-requests-with-laravel-middleware/). Under `app/Providers/` you'd find several service provider files waiting for you: `AppServiceProvider`, `AuthServiceProvider`, `EventServiceProvider`, `RouteServiceProvider`. Start a new project and they were just there — whether you needed them or not.

With Laravel 11, a significant portion of those files was removed or consolidated. Middleware registration now happens through a more fluent API in `bootstrap/app.php`. `AuthServiceProvider` and `EventServiceProvider` no longer ship by default; you create them when you actually need them.

```php
// bootstrap/app.php — Laravel 11 approach
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(EnsureTokenIsValid::class);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        // custom exception handling
    })
    ->create();
```

If you know the old `Kernel.php` approach, this feels less indirected. Everything lives in one file, readable as a chain.

## Models beyond `app/Models/User.php`

There's no radical change on the model side, but `User.php` now starts out leaner by default. Sanctum's `HasApiTokens` trait is gone from the default, and cast definitions have moved from the `$casts` property to a `casts()` method. I think that's the right call: consciously choosing what your starting point contains beats the "it was already there" assumption.

## A single service provider

In Laravel 10, registration logic was scattered across multiple service provider files. Now it all converges in a single `AppServiceProvider`. Event listeners go there, authorization gates go there.

```php
// app/Providers/AppServiceProvider.php
public function boot(): void
{
    Gate::define('update-event', function (User $user, Event $event) {
        return $user->id === $event->user_id;
    });

    Event::listen(EventCreated::class, SendEventNotification::class);
}
```

This reduces file count but creates conditions for `AppServiceProvider` to bloat. As a project grows, writing separate service provider classes still makes sense — but not having unnecessary files land by default is a good starting point.

## Broadcast channels and queue configuration

Broadcast channels no longer ship by default: `routes/channels.php` and `BroadcastServiceProvider` are gone from the skeleton, and running `php artisan install:broadcasting` brings them back. Queue connection configuration has been simplified along similar lines.

These changes introduce some learning friction on first setup, but the underlying question they're asking is: "What does this project actually need?"

## The upgrade experience

I set aside a day to migrate the Looplio API layer to Laravel 11. The official upgrade guide is a solid starting point — it lists the majority of breaking changes. The area that needs the most attention: how custom middleware is registered changed. The `handle()` signature stays the same, but registration moves from `app/Http/Kernel.php` to `bootstrap/app.php`, and the framework's own default middleware classes moved into the Illuminate namespace.

The transition definitely creates some friction, but at the end of it you have fewer files and fewer "what was this for?" moments. Two weeks in, the new structure already felt natural.

## Overall assessment

Laravel 11's skeleton simplification isn't a feature — it's a philosophy decision. Along the tension between "zero configuration, zero excess" and "everything ready to go," the framework took a step toward the former.

For small projects, this likely means a few unnecessary files you never had to delete. For larger projects, it means building the habit of consciously choosing what you add. In both cases, it makes sense.
