Passer au contenu principal
Avec Laravel 11, la structure d’application a été profondément modifiée sous le nom de « Slim Application Skeleton ». Cette page résume les points qui posent le plus souvent question, notamment lorsque vous rejoignez en cours de route un projet mis à niveau en conservant l’ancienne structure, ou si vous avez appris Laravel avec des livres ou tutoriels antérieurs à la version 10. Ce sont les questions les plus fréquemment posées sur les forums Laracasts et Stack Overflow à la sortie de Laravel 11.
Cette FAQ concerne les nouveaux projets (Laravel 11+). Pour la procédure de mise à niveau des projets existants, consultez le guide de migration.
Dans la nouvelle structure, les fichiers de configuration qui changent rarement ont été retirés du projet. Ce sont les fichiers config/ du framework qui sont utilisés à leur place.Les fichiers config/ du projet et ceux du framework sont fusionnés, avec priorité au projet. Il suffit de créer un fichier dans le projet au moment où vous souhaitez le personnaliser pour que les modifications soient prises en compte.
# Vérifier la configuration à l'intérieur du framework
cat vendor/laravel/framework/config/cors.php

# La copier dans le projet et la personnaliser
php artisan config:publish cors
Dans la nouvelle structure de Laravel 11, App\Http\Controllers\Controller est une classe vide qui n’hérite plus de Illuminate\Routing\Controller et n’utilise plus les traits ValidatesRequests / AuthorizesRequests.
Laravel 10Laravel 11
Hérite de Illuminate\Routing\ControllerClasse vide
Utilise le trait ValidatesRequestsAucun
Utilise le trait AuthorizesRequestsAucun
Références : Controller de Laravel 10 vs Controller de Laravel 11Solutions de remplacement :
// Utiliser $request->validate()
public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|string|max:255',
    ]);
}

// Utiliser Gate::authorize()
use Illuminate\Support\Facades\Gate;

public function update(Request $request, Post $post)
{
    Gate::authorize('update', $post);
}
Si vous les utilisez fréquemment, vous pouvez également restaurer App\Http\Controllers\Controller comme dans Laravel 10.
<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;

abstract class Controller extends BaseController
{
    use AuthorizesRequests, ValidatesRequests;
}
Dans la nouvelle structure, app/Http/Kernel.php a été supprimé et la configuration des middlewares se fait via withMiddleware() dans bootstrap/app.php.
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    // Tous les paramètres qui se faisaient via TrustProxies et autres middlewares
    // peuvent maintenant être configurés via les méthodes de la classe Middleware
    $middleware->trustProxies(at: '*');

    // Ajouter un middleware global
    $middleware->append(\App\Http\Middleware\MyMiddleware::class);

    // Définir un alias pour les groupes de routes
    $middleware->alias([
        'my-middleware' => \App\Http\Middleware\MyMiddleware::class,
    ]);

    // Personnaliser les groupes de middlewares Web / API
    $middleware->web(append: [
        \App\Http\Middleware\HandleInertiaRequests::class,
    ]);
})
Les fichiers de middleware personnalisés continuent d’être créés dans app/Http/Middleware/.
$this->middleware() est une fonctionnalité de Illuminate\Routing\Controller et ne peut pas être utilisée avec le contrôleur de base vide de la nouvelle structure.À la place, implémentez l’interface HasMiddleware et définissez la méthode middleware().
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;

class UserController extends Controller implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            'auth',
            new Middleware('log', only: ['index']),
            new Middleware('subscribed', except: ['index']),
        ];
    }
}
Depuis Laravel 13, l’attribut #[Middleware] est également utilisable.
use Illuminate\Routing\Controllers\HasMiddleware;
use App\Http\Middleware\EnsureTokenIsValid;

#[Middleware(EnsureTokenIsValid::class)]
class UserController extends Controller
{
    // ...
}
Référence : Middleware de contrôleur
authorizeResource() dépend du trait AuthorizesRequests et ne peut donc pas être utilisée avec le contrôleur de base vide de la nouvelle structure.Plusieurs approches sont possibles.1. Restaurer le contrôleur de base à la spécification Laravel 10 (le plus simple)
// app/Http/Controllers/Controller.php
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Routing\Controller as BaseController;

abstract class Controller extends BaseController
{
    use AuthorizesRequests;
}
Cela rend $this->authorizeResource() à nouveau utilisable.2. Appliquer l’attribut #[Authorize] de Laravel 13 à chaque méthode
use Illuminate\Routing\Attributes\Controllers\Authorize;
use App\Models\Post;

class PostController extends Controller
{
    #[Authorize('view', 'post')]
    public function show(Post $post) { /* ... */ }

    #[Authorize('update', 'post')]
    public function update(Request $request, Post $post) { /* ... */ }
}
Dans la nouvelle structure, app/Console/Kernel.php a été supprimé et l’emplacement de configuration des tâches planifiées a changé.À écrire dans routes/console.php (recommandé) :
// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('emails:send')->daily();
Schedule::job(new SendEmails)->everyFiveMinutes();
À écrire dans bootstrap/app.php :
->withSchedule(function (Schedule $schedule) {
    $schedule->command('emails:send')->daily();
})
Dans la nouvelle structure, EventServiceProvider a été supprimé et il n’est plus nécessaire d’enregistrer manuellement les événements et les écouteurs.Mécanisme d’enregistrement automatique : en déclarant le type de la classe d’événement dans l’argument de la méthode handle() de la classe d’écouteur, l’enregistrement est effectué automatiquement.
namespace App\Listeners;

use App\Events\OrderShipped;

class SendShipmentNotification
{
    // Il suffit d'indiquer la classe d'événement comme argument de handle() pour qu'elle soit enregistrée automatiquement
    public function handle(OrderShipped $event): void
    {
        // ...
    }
}
Si un enregistrement manuel est nécessaire, faites-le dans AppServiceProvider::boot().
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(
        OrderShipped::class,
        SendShipmentNotification::class,
    );
}
Dans la nouvelle structure, la gestion de la liste des service providers est passée de config/app.php à bootstrap/providers.php.
// bootstrap/providers.php
return [
    App\Providers\AppServiceProvider::class,
    App\Providers\MyCustomServiceProvider::class, // ← à ajouter ici
];
Les providers créés avec artisan make:provider sont automatiquement ajoutés dans ce fichier.
Dans la nouvelle structure, app/Exceptions/Handler.php a été supprimé et la configuration des exceptions se fait via withExceptions() dans bootstrap/app.php.
// bootstrap/app.php
->withExceptions(function (Exceptions $exceptions) {
    // Ne pas reporter certaines exceptions
    $exceptions->dontReport(InvalidOrderException::class);

    // Rendu personnalisé
    $exceptions->render(function (InvalidOrderException $e, Request $request) {
        return response()->view('errors.invalid-order', status: 500);
    });

    // Changer la redirection en cas de non-authentification
    $exceptions->shouldRenderJsonWhen(function (Request $request, Throwable $e) {
        return $request->is('api/*');
    });
})
La personnalisation des routes se fait via withRouting() dans bootstrap/app.php.Ajouter un fichier de routes :
->withRouting(
    web: __DIR__.'/../routes/web.php',
    then: function () {
        Route::middleware('web')
            ->prefix('admin')
            ->group(base_path('routes/admin.php'));
    },
)
Contrôle complet (équivalent au RouteServiceProvider de Laravel 10) :En spécifiant using, l’enregistrement par défaut des routes de Laravel est totalement désactivé et vous contrôlez tout vous-même.
->withRouting(
    using: function () {
        Route::middleware('web')
            ->group(base_path('routes/web.php'));

        Route::middleware('api')
            ->prefix('api')
            ->group(base_path('routes/api.php'));
    },
)
En ajoutant une clé providers dans config/app.php, celle-ci est fusionnée avec le config/app.php du framework et prise en compte.
// config/app.php
use Illuminate\Support\ServiceProvider;

return [
    // ...
    'providers' => ServiceProvider::defaultProviders()->replace([
        Illuminate\Foo\FooServiceProvider::class => Bar\BarServiceProvider::class,
    ])->toArray(),
];
La méthode replace() permet de substituer un provider par défaut par votre propre implémentation.
Depuis Laravel 11, les fonctionnalités API ne sont pas incluses par défaut ; il faut les installer séparément lorsque vous en avez besoin.
php artisan install:api
Cette commande crée et configure les éléments suivants :
  • routes/api.php
  • La configuration de Laravel Sanctum pour l’authentification API
  • L’enregistrement des routes API dans bootstrap/app.php
Depuis Laravel 11, les fonctionnalités de broadcasting ne sont pas non plus incluses par défaut ; il faut les installer séparément lorsque vous en avez besoin.
php artisan install:broadcasting
Cette commande crée et configure les éléments suivants :
  • routes/channels.php
  • L’installation de Laravel Reverb
  • Les fichiers de configuration de broadcasting
Consultez le contenu de bootstrap/app.php.Nouvelle structure Laravel 11+ (ou projet migré) :
// bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(...)
    ->withMiddleware(...)
    ->withExceptions(...)
    ->create();
Projet mis à niveau depuis Laravel 10 tout en gardant l’ancienne structure :
// bootstrap/app.php
$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);
// ...
Si le format est return Application::configure(..., il s’agit de la nouvelle structure ; sinon, c’est un projet mis à niveau qui a conservé l’ancienne. Pour la procédure de migration d’un projet ancienne structure vers la nouvelle, consultez le guide de migration.

Pages associées

Structure d'application Laravel 11+

Vue d’ensemble de la nouvelle structure d’application et détail de l’implémentation interne de ApplicationBuilder.

Guide de migration de l'ancienne vers la nouvelle structure

Procédure pour migrer d’une ancienne structure Laravel 10 vers la nouvelle structure Laravel 11+.
Dernière modification le 13 juillet 2026