Laravel Request Lifecycle
Understand the journey of an HTTP request through Laravel
Understanding the request lifecycle is crucial for debugging, optimization, and building middleware.
The Journey of a Request:
1. Entry Point (public/index.php) - Request enters here
2. Autoloader - Composer autoloads classes
3. Bootstrap - Application is created (bootstrap/app.php)
4. HTTP Kernel - Request is captured and sent through middleware
5. Router - Finds matching route
6. Middleware - Route-specific middleware runs
7. Controller - Action is executed
8. Response - Generated and sent back through middleware
9. Termination - Application sends response to browser
Why This Matters:
• Middleware order affects request handling
• Understanding this helps debug issues
• Know when database connections are made
• Optimize performance at the right stage
Real-World Example:
If your API is slow, knowing the lifecycle helps you identify whether it's middleware (authentication), the controller (business logic), or database queries causing the delay.
The Journey of a Request:
1. Entry Point (public/index.php) - Request enters here
2. Autoloader - Composer autoloads classes
3. Bootstrap - Application is created (bootstrap/app.php)
4. HTTP Kernel - Request is captured and sent through middleware
5. Router - Finds matching route
6. Middleware - Route-specific middleware runs
7. Controller - Action is executed
8. Response - Generated and sent back through middleware
9. Termination - Application sends response to browser
Why This Matters:
• Middleware order affects request handling
• Understanding this helps debug issues
• Know when database connections are made
• Optimize performance at the right stage
Real-World Example:
If your API is slow, knowing the lifecycle helps you identify whether it's middleware (authentication), the controller (business logic), or database queries causing the delay.
Code Examples
Step 1-3: Entry Point & Bootstrap
💡 Solution
php
<?php
// public/index.php - The entry point
define('LARAVEL_START', microtime(true));
// Step 1: Register Composer autoloader
require __DIR__.'/../vendor/autoload.php';
// Step 2: Bootstrap the application
$app = require_once __DIR__.'/../bootstrap/app.php';
// Step 3: Create HTTP Kernel and handle request
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
// Send response to browser
$response->send();
// Perform termination tasks (logging, cleanup)
$kernel->terminate($request, $response);
// This is what happens when you visit your Laravel app!
// Every request goes through this exact flow.
💡 The index.php file is the single entry point for all requests. It bootstraps Laravel and creates the HTTP Kernel to handle the request.
Step 4-5: HTTP Kernel & Middleware Pipeline
💡 Solution
php
<?php
// app/Http/Kernel.php
class Kernel extends HttpKernel
{
// Global middleware (runs on EVERY request)
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
// Middleware groups
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
}
// Request flows through middleware like this:
// Request → TrustProxies → ValidatePostSize → TrimStrings
// → EncryptCookies → StartSession → VerifyCsrfToken
// → YOUR CONTROLLER
// → VerifyCsrfToken → StartSession → EncryptCookies (back)
// → Response
// Think of it as an onion - request goes IN, response goes OUT
💡 Global middleware runs on every request. Middleware wraps your controller like layers of an onion - the request goes through each layer in order, then the response comes back through them in reverse.
Step 6-7: Router & Controller Execution
💡 Solution
php
<?php
// routes/web.php
Route::get('/orders/{id}', [OrderController::class, 'show'])
->middleware(['auth', 'verified']);
// What happens internally:
// 1. Router matches the URI pattern
// 2. Router checks route-specific middleware (auth, verified)
// 3. Middleware pipeline executes (in addition to global middleware)
// 4. Route model binding occurs (if using implicit binding)
// 5. Controller method is resolved from Service Container
// 6. Dependencies are injected
// OrderController.php
class OrderController extends Controller
{
// These dependencies are auto-injected!
public function show(Order $order, OrderRepository $repository)
{
// $order is already loaded via route model binding
// $repository is resolved from Service Container
$order->loadMissing(['items', 'customer']);
return view('orders.show', [
'order' => $order,
'related' => $repository->getRelated($order),
]);
}
}
// Timeline at this point:
// 0-50ms: Middleware execution
// 50-60ms: Route matching
// 60-70ms: Controller resolution
// 70-200ms: Your business logic (database queries, etc.)
// 200ms+: View rendering
💡 After middleware, the router finds the matching route and executes route-specific middleware. Then it resolves the controller from the container with all dependencies injected.
Step 8-9: Response & Termination
💡 Solution
php
<?php
// Controller returns a response
return response()->json([
'success' => true,
'order' => $order,
], 200);
// OR returns a view (converted to Response internally)
return view('orders.show', compact('order'));
// Response travels BACK through middleware (in reverse)
// ← Response leaves Controller
// ← ShareErrorsFromSession (adds flash messages to session)
// ← VerifyCsrfToken (no action on response)
// ← StartSession (saves session data)
// ← EncryptCookies (encrypts cookies)
// → Response sent to browser!
// After response is sent, termination callbacks run:
public function terminate($request, $response)
{
// Log analytics (doesn't slow down response)
Analytics::track($request);
// Queue cleanup jobs
Queue::push(new CleanupTempFiles());
// These run AFTER the user receives the response
// Perfect for slow tasks that don't affect UX
}
// Full lifecycle timing example:
// 0ms: Request arrives at index.php
// 1ms: Application bootstrapped
// 5ms: Global middleware executed
// 10ms: Route matched
// 15ms: Route middleware executed
// 20ms: Controller resolved
// 150ms: Controller logic + DB queries
// 180ms: View rendered
// 185ms: Response through middleware
// 200ms: Response sent to user ← User sees page!
// 201ms+: Termination tasks (user doesn't wait)
💡 The response goes back through middleware in reverse order. After sending the response, termination callbacks run for cleanup tasks - the user doesn't wait for these!