Originally published on laravel.learnio.dev — part of the Laravel best practices course. View this lesson on the original site.

In this lesson

Controllers move request-handling logic out of route closures and into dedicated classes. This keeps routes clean and makes feature behavior easier to test.

MVC in Laravel, in practical terms

Laravel follows an MVC-style structure:

  • Model: data and domain representation (usually Eloquent models in app/Models).
  • View: presentation layer (Blade templates in resources/views).
  • Controller: request orchestration (classes in app/Http/Controllers).

Controller code should coordinate work, not contain all business rules itself.

flowchart LR
  A[Request] --> B[Route]
  B --> C[Controller]
  C --> D[Model or service]
  C --> E[View or JSON response]

First controller example

Create a controller:

php artisan make:controller HomeController

Add an action:

namespace App\\Http\\Controllers;

class HomeController extends Controller
{
    public function index()
    {
        return view('home');
    }
}

Use it in routes/web.php:

use App\\Http\\Controllers\\HomeController;

Route::get('/home', [HomeController::class, 'index'])->name('home');

Why this structure helps

  • routes stay declarative,
  • controller actions become easy to test,
  • logic can later move into services without route rewrites,
  • MVC boundaries make code reviews clearer.

In later chapters, you will deepen each MVC part, models (data), views (presentation), and controller/service architecture.

From Laravel best practices — What is Laravel?