If you have opened a fresh Laravel project recently after a few years away, the first reaction is usually the same: "Where did everything go?" Laravel 11 introduced a dramatically slimmer application skeleton, and Laravel 12 continues in the same direction β€” refining the structure rather than reinventing it. This post walks through what the modern skeleton looks like, why the framework moved this way, and how to work productively inside it.

The philosophy behind the slim skeleton

For a decade, every Laravel application shipped with a thick layer of boilerplate: an app/Http/Middleware directory full of framework middleware, a Kernel.php for HTTP and another for the console, a stack of service providers, and a config directory containing every option the framework supports. Most of those files were never edited. They existed only so that you could edit them, and they made every upgrade a diff-matching exercise.

The slim structure flips the default. Framework behavior now lives inside the framework, and your application only contains the code that is genuinely yours. A brand-new Laravel 12 app ships with a single service provider (AppServiceProvider), no middleware classes, no HTTP or console kernels, and a much shorter list of top-level files. Everything you removed is still configurable β€” it is just configured in one place.

bootstrap/app.php is the new control center

The most important file to understand in a modern Laravel application is bootstrap/app.php. It replaces the old kernels and most of the "register something in a provider" patterns with a fluent builder:

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->alias([
            'admin' => EnsureUserIsAdmin::class,
        ]);
        $middleware->throttleApi('120,1');
    })
    ->withExceptions(function (Exceptions $exceptions) {
        $exceptions->dontReport(PaymentDeclinedException::class);
    })->create();

Middleware aliases, global middleware, middleware groups, exception reporting rules, and route registration all live here. When you need to customize something that used to require hunting through Kernel.php, this is almost always where it goes now. The health: '/up' line also gives you a built-in health-check endpoint out of the box, which is genuinely handy for load balancers and uptime monitors.

Scheduling moved to routes/console.php

The console kernel is gone, and with it the schedule() method you may remember. Scheduled tasks are now declared in routes/console.php using the Schedule facade, right next to any closure-based Artisan commands:

use Illuminate\Support\Facades\Schedule;

Schedule::command('reports:generate')->dailyAt('06:00');
Schedule::job(new PruneStaleSessions)->everyThirtyMinutes();
Schedule::command('backup:run')->weeklyOn(1, '02:00')
    ->onOneServer()
    ->withoutOverlapping();

This is a small change with a pleasant side effect: your entire scheduling story is visible in one short file instead of being buried inside a class. Class-based commands in app/Console/Commands are still auto-discovered, so you only touch this file to register schedules or quick closure commands.

What Laravel 12 itself brings

Laravel 12 is deliberately a maintenance-minded release. After two structurally disruptive versions, the framework team focused on dependency upgrades, developer experience, and keeping the upgrade path short β€” for many applications, upgrading from 11 to 12 takes minutes. A few highlights worth knowing:

  • New starter kits. The long-serving Breeze and Jetstream kits were succeeded by fresh starter kits for React, Vue, and Livewire, built around Inertia 2 and modern tooling, with optional WorkOS-powered authentication (social login, passkeys, SSO).
  • Streamlined defaults. The skeleton continues to trim: casts are declared in a casts() method on models, configuration files can be partially published with php artisan config:publish, and per-second rate limiting is available on throttles.
  • First-party ecosystem maturity. Tools that debuted around Laravel 11 β€” Reverb for WebSockets, Pulse for application health dashboards, Pennant for feature flags β€” are now the assumed defaults rather than experiments, and Pest is the default testing framework for new applications.

Working without the old files

The most common friction for developers returning to Laravel is muscle memory. Here is a quick translation table for the tasks people reach for most often:

  1. Register global middleware: $middleware->append(...) in bootstrap/app.php instead of the HTTP kernel.
  2. Change model casts: define a casts() method returning an array, instead of a $casts property (the property still works, but the method can call static helpers like AsCollection::using()).
  3. Customize exception rendering: use ->withExceptions() rather than editing app/Exceptions/Handler.php, which no longer exists.
  4. Add a service provider: php artisan make:provider still works and auto-registers it in bootstrap/providers.php.
  5. API routes: a fresh app has no routes/api.php until you run php artisan install:api, which also installs Sanctum.

None of the old capabilities were removed β€” the framework simply stopped forcing you to own files you never change. If you genuinely need a config file that is not published, config:publish brings it back into your repo.

Should you restructure existing applications?

No β€” and the Laravel team is explicit about this. Applications upgraded from Laravel 10 keep their kernels, middleware, and full config directory, and that structure remains fully supported. The slim skeleton is the default for new applications, not a migration requirement. If you enjoy the leaner layout you can gradually adopt pieces of it, but there is zero pressure and no deprecation clock ticking.

Closing thoughts

The slim application structure is the biggest change to day-to-day Laravel development since the framework adopted PSR-4, and Laravel 12 confirms it is here to stay. Once you internalize that bootstrap/app.php is the configuration hub and routes/console.php owns scheduling, the new skeleton stops feeling empty and starts feeling honest: every file in your project is there because you put it there. For teams starting new projects in 2026, that is a very comfortable place to build from.

Related Service

πŸ’» Web Development

Custom websites and web applications built with PHP, Laravel, WordPress, and React β€” fast, secure, scalable, and tailored to your business goals.

Explore Web Development →