Introduction

Every HTTP request to a Laravel app follows the same journey: public/index.php, the kernel, middleware, the router, a controller, and a response. This lesson traces that journey so you can debug effectively and know where to put custom logic.

Key Concepts

  • Entry point: public/index.php is the only PHP file the web server serves directly.
  • HTTP kernel: Loads configuration, registers providers, and boots the application.
  • Middleware pipeline: An onion of layers that wrap the controller — each middleware runs code before and after $next($request).
  • Router: Matches the request URL to a route definition and resolves the controller.
  • Response: Whatever the controller returns is passed back through middleware to the browser.

Real World Context

When a page suddenly 500s in production, knowing the request lifecycle tells you where to look: the middleware list for auth issues, the router for wrong URL matches, the controller for business-logic bugs, and bootstrap/app.php for anything bootstrap-related.

Deep Dive

Understanding how Laravel processes a request helps you write better applications and debug issues effectively. Let's trace a request from browser to response.

The Journey of a Request

┌───────────────────────────────────────────────────────────────┐
│                        HTTP Request                            │
│                   GET /users?page=1                            │
└───────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌───────────────────────────────────────────────────────────────┐
│ 1. Entry Point: public/index.php                              │
│    - Loads Composer autoloader                                │
│    - Creates Application instance                             │
└───────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌───────────────────────────────────────────────────────────────┐
│ 2. HTTP Kernel                                                 │
│    - Loads configuration                                       │
│    - Registers service providers                               │
│    - Boots service providers                                   │
└───────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌───────────────────────────────────────────────────────────────┐
│ 3. Middleware Pipeline                                         │
│    - Global middleware (HTTPS, maintenance mode)              │
│    - Route middleware (auth, throttle)                        │
└───────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌───────────────────────────────────────────────────────────────┐
│ 4. Router                                                      │
│    - Matches URL to route                                     │
│    - Resolves controller/closure                              │
└───────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌───────────────────────────────────────────────────────────────┐
│ 5. Controller/Action                                           │
│    - Handles business logic                                   │
│    - Returns response                                         │
└───────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌───────────────────────────────────────────────────────────────┐
│ 6. Response                                                    │
│    - Passes back through middleware                           │
│    - Sent to browser                                          │
└───────────────────────────────────────────────────────────────┘

Step 1: Entry Point

Every request enters through public/index.php:

php
<?php

use Illuminate\Http\Request;

define('LARAVEL_START', microtime(true));

// Register the Composer autoloader
require __DIR__.'/../vendor/autoload.php';

// Bootstrap Laravel and handle the request
(require_once __DIR__.'/../bootstrap/app.php')
    ->handleRequest(Request::capture());

The bootstrap/app.php file creates the Application:

php
<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

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) {
        // Configure middleware here
    })
    ->withExceptions(function (Exceptions $exceptions) {
        // Configure exception handling here
    })->create();

Step 2: The HTTP Kernel

The HTTP kernel bootstraps the application:

  1. Loads environment (.env file)
  2. Loads configuration (config/*.php)
  3. Registers service providers (register() methods)
  4. Boots service providers (boot() methods)

Step 3: Middleware Pipeline

Middleware filters requests before they reach your code. In Laravel 11+ (including Laravel 13) all middleware is registered in bootstrap/app.php via the withMiddleware() closure — the old app/Http/Kernel.php file has been removed.

php
// bootstrap/app.php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(/* ... */)
    ->withMiddleware(function (Middleware $middleware) {
        // Add a middleware to every request (global middleware)
        $middleware->append(\App\Http\Middleware\LogRequests::class);

        // Append to the default 'web' group (sessions, cookies, CSRF)
        $middleware->web(append: [
            \App\Http\Middleware\EnsureUserIsSubscribed::class,
        ]);
    })
    ->create();

The default web group Laravel applies automatically contains EncryptCookies, AddQueuedCookiesToResponse, StartSession, ShareErrorsFromSession, PreventRequestForgery (the CSRF middleware, renamed from VerifyCsrfToken in Laravel 13), and SubstituteBindings. The default api group is lean: just SubstituteBindings.

Middleware executes in order:

Request → M1 → M2 → M3 → Controller → M3 → M2 → M1 → Response

Step 4: Routing

The router matches the URL to a route:

php
// routes/web.php
Route::get('/users', [UserController::class, 'index']);

// Request: GET /users
// Matched: UserController@index

Routing also runs route-specific middleware:

php
Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware('auth');  // Only authenticated users

Step 5: Controller/Action

The controller handles the request:

php
class UserController extends Controller
{
    public function index()
    {
        $users = User::paginate(15);

        return view('users.index', ['users' => $users]);
    }
}

Dependencies are automatically injected:

php
public function store(StoreUserRequest $request)  // Auto-validated!
{
    User::create($request->validated());
    return redirect()->route('users.index');
}

Step 6: Response

The response travels back through middleware:

php
// Middleware can modify responses
public function handle($request, Closure $next)
{
    $response = $next($request);  // Get response from controller

    // Modify response
    $response->header('X-Custom-Header', 'Value');

    return $response;
}

Finally, the response is sent to the browser.

Common Pitfalls

  1. Adding request logic to controllers that belongs in middleware — If ten controllers all check for an API key, that is middleware's job, not each controller's.
  2. Forgetting that $next($request) runs the rest of the pipeline — Code after $next runs on the way out, not before the controller.

Best Practices

  1. Log at the kernel level for debugging — A custom middleware that logs the URL and duration is the fastest way to spot slow requests.
  2. Keep controllers thin — They should coordinate services and return views. Cross-cutting concerns live in middleware.

Summary

  • Every request enters through public/index.php.
  • The HTTP kernel boots the framework on each request.
  • Middleware runs before AND after the controller — code after $next runs on the way back out.
  • The router maps URLs to controllers or closures.
  • The controller's return value becomes the response sent to the browser.
✓ Completed