Request to Response

From public/index.php to a Response

Apache's front-controller rewrite (Front-Controller Routing) sends every request that is not a real file to public/index.php. Without its use lines and comments, the skeleton's file is five statements:

public/index.php in Laravel 13.33.0 (use lines and comments omitted)PHP
define('LARAVEL_START', microtime(true));
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
    require $maintenance;
}
require __DIR__.'/../vendor/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
$app->handleRequest(Request::capture());

The maintenance check runs before the autoloader, so a pre-rendered page can be served while vendor/ is half-updated (Error Pages). handleRequest() resolves the HTTP kernel, calls $kernel->handle($request)->send(), then $kernel->terminate() (Terminable Middleware).

The lifecycle of one HTTP request in a Laravel 13 application
The lifecycle of one HTTP request in a Laravel 13 2,157 application

The tracer below, appended to bootstrap/app.php, logs milliseconds since LARAVEL_START using events and callbacks the framework already fires. AppServiceProvider and a /products/{id} route call the same app('trace'). The output is storage/logs/trace.log after a warm request to /products/42.

Instrumenting the lifecycle (appended to bootstrap/app.php, before return $app)PHP
$trace = function (string $step): void {
    $ms = (microtime(true) - LARAVEL_START) * 1000;
    file_put_contents(dirname(__DIR__).'/storage/logs/trace.log',
        sprintf("%6.2f ms  %s\n", $ms, $step), FILE_APPEND);
};
$app->instance('trace', $trace);
$app['events']->listen('bootstrapping: *', fn ($name) => $trace(class_basename($name)));
$app->booted(fn () => $trace('all providers booted'));
$app['events']->listen(RouteMatched::class,
    fn ($e) => $trace('route matched: '.$e->route->uri()));
$app['events']->listen(RequestHandled::class, fn ($e) => $trace('kernel returns '
    .$e->response->getStatusCode()));
$app->terminating(fn () => $trace('terminating, after send()'));
$trace('bootstrap/app.php returns');
Output
  0.57 ms  bootstrap/app.php returns
  1.02 ms  LoadEnvironmentVariables
  1.62 ms  LoadConfiguration
  3.37 ms  HandleExceptions
  3.44 ms  RegisterFacades
  3.56 ms  RegisterProviders
  4.54 ms  AppServiceProvider::register
  4.60 ms  BootProviders
  5.25 ms  AppServiceProvider::boot
  5.87 ms  all providers booted
  6.52 ms  route matched: products/{id}
  7.86 ms  route action runs
  9.02 ms  kernel returns 200
  9.41 ms  terminating, after send()

Each line is written as its stage starts, so the gap to the next line is its cost. Bootstrapping took about 60% of this 9 ms request; the 1.3 ms before "route action runs" is the web group's cookies, session and CSRF.