Vai al contenuto principale
Con Laravel 11 la struttura dell’applicazione è cambiata in modo significativo, prendendo il nome di “Slim Application Skeleton”. Questa FAQ raccoglie i punti su cui è facile disorientarsi se ti unisci a un progetto aggiornato ma con struttura vecchia, o hai studiato su libri e tutorial di Laravel 10 o precedenti. Sono domande che al rilascio di Laravel 11 comparivano spesso su Laracasts, Stack Overflow e simili.
Questa FAQ si riferisce ai nuovi progetti (Laravel 11 e successivi). Per l’upgrade di progetti esistenti consulta la guida di migrazione.
Nella nuova struttura i file di config che cambiano raramente sono stati rimossi dal progetto. Al loro posto vengono usati i config/ interni del framework.Il config/ del progetto e quello del framework vengono fusi, con precedenza al progetto. Quando ti serve personalizzare, crea il file e la modifica verrà applicata.
# controlla il config interno del framework
cat vendor/laravel/framework/config/cors.php

# copia nel progetto per personalizzare
php artisan config:publish cors
Nella nuova struttura di Laravel 11 App\Http\Controllers\Controller è una classe vuota: non estende Illuminate\Routing\Controller e non usa i trait ValidatesRequests / AuthorizesRequests.
Laravel 10Laravel 11
Estende Illuminate\Routing\ControllerClasse vuota
Usa il trait ValidatesRequestsNo
Usa il trait AuthorizesRequestsNo
Riferimenti: Controller di Laravel 10 vs Controller di Laravel 11Alternative:
// usa $request->validate()
public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|string|max:255',
    ]);
}

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

public function update(Request $request, Post $post)
{
    Gate::authorize('update', $post);
}
Se ti serve spesso, puoi anche ripristinare App\Http\Controllers\Controller come in 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;
}
Nella nuova struttura app/Http/Kernel.php è stato rimosso e le impostazioni dei middleware si configurano in bootstrap/app.php con withMiddleware().
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    // Le impostazioni configurate su TrustProxies e simili si fanno con i metodi della classe Middleware
    $middleware->trustProxies(at: '*');

    // aggiungere middleware globali
    $middleware->append(\App\Http\Middleware\MyMiddleware::class);

    // alias per i gruppi di rotte
    $middleware->alias([
        'my-middleware' => \App\Http\Middleware\MyMiddleware::class,
    ]);

    // personalizzare i gruppi Web / API
    $middleware->web(append: [
        \App\Http\Middleware\HandleInertiaRequests::class,
    ]);
})
I file dei middleware personalizzati vanno comunque in app/Http/Middleware/.
$this->middleware() è una funzionalità di Illuminate\Routing\Controller: nel controller base vuoto della nuova struttura non è disponibile.In sostituzione implementa l’interfaccia HasMiddleware e definisci il metodo 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']),
        ];
    }
}
Da Laravel 13 puoi anche usare l’attributo #[Middleware].
use Illuminate\Routing\Controllers\HasMiddleware;
use App\Http\Middleware\EnsureTokenIsValid;

#[Middleware(EnsureTokenIsValid::class)]
class UserController extends Controller
{
    // ...
}
Riferimento: Middleware dei controller
authorizeResource() dipende dal trait AuthorizesRequests: nel controller base vuoto della nuova struttura non è disponibile.Ci sono più approcci.1. Ripristinare il controller base allo stile Laravel 10 (il più semplice)
// app/Http/Controllers/Controller.php
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Routing\Controller as BaseController;

abstract class Controller extends BaseController
{
    use AuthorizesRequests;
}
In questo modo $this->authorizeResource() torna disponibile.2. Applicare l’attributo #[Authorize] di Laravel 13 a ciascun metodo
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) { /* ... */ }
}
Nella nuova struttura app/Console/Kernel.php è stato rimosso e il posto in cui configurare lo scheduler è cambiato.Scrivere in routes/console.php (consigliato):
// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('emails:send')->daily();
Schedule::job(new SendEmails)->everyFiveMinutes();
Scrivere in bootstrap/app.php:
->withSchedule(function (Schedule $schedule) {
    $schedule->command('emails:send')->daily();
})
Nella nuova struttura EventServiceProvider è stato rimosso e non serve più registrare a mano eventi e listener.Meccanismo di registrazione automatica: se dichiari il tipo dell’evento come argomento del metodo handle() del listener, la registrazione avviene automaticamente.
namespace App\Listeners;

use App\Events\OrderShipped;

class SendShipmentNotification
{
    // basta tipizzare la classe evento in handle() per la registrazione automatica
    public function handle(OrderShipped $event): void
    {
        // ...
    }
}
Se hai bisogno di registrazione manuale, fallo in AppServiceProvider::boot().
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(
        OrderShipped::class,
        SendShipmentNotification::class,
    );
}
Nella nuova struttura la gestione dell’elenco dei service provider è passata da config/app.php a bootstrap/providers.php.
// bootstrap/providers.php
return [
    App\Providers\AppServiceProvider::class,
    App\Providers\MyCustomServiceProvider::class, // ← aggiungi qui
];
I provider creati con artisan make:provider vengono aggiunti automaticamente in questo file.
Nella nuova struttura app/Exceptions/Handler.php è stato rimosso e la configurazione delle eccezioni si fa in bootstrap/app.php con withExceptions().
// bootstrap/app.php
->withExceptions(function (Exceptions $exceptions) {
    // non riportare eccezioni specifiche
    $exceptions->dontReport(InvalidOrderException::class);

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

    // condizione per rendere in JSON quando non autenticato
    $exceptions->shouldRenderJsonWhen(function (Request $request, Throwable $e) {
        return $request->is('api/*');
    });
})
La personalizzazione delle rotte si fa in bootstrap/app.php con withRouting().Aggiungere un file di rotte:
->withRouting(
    web: __DIR__.'/../routes/web.php',
    then: function () {
        Route::middleware('web')
            ->prefix('admin')
            ->group(base_path('routes/admin.php'));
    },
)
Controllo completo (equivalente al RouteServiceProvider di Laravel 10):Con using disabiliti completamente la registrazione delle rotte di default e gestisci tutto tu.
->withRouting(
    using: function () {
        Route::middleware('web')
            ->group(base_path('routes/web.php'));

        Route::middleware('api')
            ->prefix('api')
            ->group(base_path('routes/api.php'));
    },
)
Aggiungendo la chiave providers in config/app.php viene fusa con il config/app.php del framework.
// config/app.php
use Illuminate\Support\ServiceProvider;

return [
    // ...
    'providers' => ServiceProvider::defaultProviders()->replace([
        Illuminate\Foo\FooServiceProvider::class => Bar\BarServiceProvider::class,
    ])->toArray(),
];
Con replace() sostituisci un provider di default con la tua implementazione.
Da Laravel 11 le funzionalità API non sono più incluse di default; le installi quando servono.
php artisan install:api
Questo comando crea/configura:
  • routes/api.php
  • la configurazione di Laravel Sanctum per l’autenticazione API
  • la registrazione delle rotte API in bootstrap/app.php
Da Laravel 11 anche il broadcasting non è più incluso di default; lo installi separatamente quando serve.
php artisan install:broadcasting
Questo comando crea/configura:
  • routes/channels.php
  • le impostazioni di installazione di Laravel Reverb
  • i file di configurazione del broadcasting
Controlla il contenuto di bootstrap/app.php.Nuova struttura da Laravel 11 (o già migrata):
// bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(...)
    ->withMiddleware(...)
    ->withExceptions(...)
    ->create();
Progetto aggiornato mantenendo la vecchia struttura pre-Laravel 11:
// 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
);
// ...
Se vedi il formato return Application::configure(... è la nuova struttura, altrimenti si tratta di un progetto aggiornato senza aver migrato lo scheleton. Per la procedura di migrazione consulta la guida di migrazione.

Pagine correlate

Struttura dell'applicazione da Laravel 11

Panoramica completa della nuova struttura dell’applicazione e implementazione interna di ApplicationBuilder.

Guida alla migrazione dalla vecchia alla nuova struttura

Procedura per migrare dall’app skeleton di Laravel 10 alla nuova struttura da Laravel 11.
Ultima modifica il 13 luglio 2026