Reader Stacks

A Complete Guide to the Laravel Response

response(), the Response facade, and the difference between returning a string, a view, JSON, or a full Response object from a controller.

Every Laravel route or controller method returns something that gets converted into an HTTP response — understanding the different ways to build that response, and when to reach for each, avoids a lot of trial and error.

The simplest case: returning a string

Route::get('/ping', fn () => 'pong');

Laravel automatically wraps a returned string in a 200 response with a text/html content type.

The response() helper

return response('Not allowed', 403);

response() takes the body as the first argument and the status code as the second — the most common way to return a specific status code with a simple body.

JSON responses

return response()->json(['status' => 'ok', 'id' => $order->id]);

This sets the Content-Type: application/json header and serializes the array automatically. Returning an Eloquent model or collection directly from a route also auto-converts to JSON — response()->json() is only necessary when you need to also set a custom status code or headers.

Setting headers and cookies fluently

return response('Created', 201)
    ->header('X-Request-Id', $requestId)
    ->cookie('last_visit', now()->toDateString());

Redirects

return redirect()->route('dashboard');
return redirect()->back()->withErrors(['email' => 'Already taken']);

The underlying Response class

Every one of these shortcuts ultimately produces an Illuminate\Http\Response (or a subclass like JsonResponse or RedirectResponse) — reaching for the class directly is rarely necessary in application code, but it's worth knowing it's there when a package or test needs to inspect exactly what a route returned.