Route::put

Registers a route that answers PUT requests, replacing a resource in full.

Signature
put(string $uri, array|string|callable $action = null): Illuminate\Routing\Route

Parameters

ParameterTypeDescription
$$uristringThe URI pattern to match; the resource identifier is normally a {param} segment.
$$actionoptionalarray|string|callable= nullA closure, a [Controller::class, 'method'] array, an invokable controller class name, or a 'Controller@method' string.

Return value

Illuminate\Routing\RouteThe registered Route instance, ready for chained calls to name(), middleware(), where() and so on.

Errors

Nothing at registration. At request time a mismatch on a where() constraint or a missing bound model returns 404, and a web form without @csrf returns 419.

Route::put registers a handler for the PUT verb, whose HTTP semantics are replace the resource in full. PATCH is the partial-update counterpart. Laravel does not enforce the distinction — both end up in the same update method in a resource controller — but clients and proxies do care, and an API contract that says PUT should accept a complete representation.

When to reach for it

A settings screen that submits every field, an API client that sends the whole object back, an idempotent "put this record into exactly this state" operation. Retrying a PUT should be safe; that is the property that distinguishes it from POST.

What trips people up

  • Browsers cannot send PUT from a form. HTML forms support only GET and POST, so Laravel supports method spoofing: post the form with a _method field set to PUT — the @method('PUT') Blade directive writes it — and the router treats the request as a PUT. JavaScript clients send the real verb and need no spoofing.
  • PUT does not imply PATCH. Route::put matches PUT only. A client sending PATCH gets a 405. Resource routes avoid this by registering the update URI for both verbs; do the same manually with Route::match(['put', 'patch'], ...).
  • CSRF still applies to spoofed PUT requests in routes/web.php.

Example

Example · php
<?php

use App\Http\Controllers\PhotoController;
use Illuminate\Support\Facades\Route;

Route::put('/photos/{photo}', [PhotoController::class, 'update'])
    ->whereNumber('photo')
    ->middleware('auth')
    ->name('photos.update');

// Accept partial updates on the same URI:
Route::match(['put', 'patch'], '/settings', [SettingsController::class, 'update'])
    ->name('settings.update');

echo route('photos.update', ['photo' => 12]);
// http://example.com/photos/12

When to use it

  • Replace a user profile with the full set of fields submitted from an edit form.
  • Expose an idempotent API endpoint that overwrites a document by id.
  • Register a single URI that accepts both PUT and PATCH with Route::match.
  • Constrain the id segment with whereNumber so bad ids 404 before the controller runs.

Frequently asked questions

What is the difference between Route::put and Route::patch?

PUT means replace the whole resource, PATCH means update part of it. Laravel routes them separately but a resource controller sends both to the same update method, so the distinction is a contract with your clients rather than something the framework enforces.

Why does my HTML form not reach my PUT route?

Browsers only submit GET and POST. Post the form and add @method('PUT'), which renders a hidden _method field that Laravel reads to spoof the verb.

Can one route accept both PUT and PATCH?

Yes, use Route::match(['put', 'patch'], '/photos/{photo}', ...). That is exactly what Route::resource registers for the update action.

More examples

Method spoofing from a Blade form

The form's real HTTP method is POST, but the hidden _method field makes Laravel dispatch it to the PUT route. Both @csrf and @method('PUT') are required here: drop the first and you get a 419, drop the second and the request looks for a POST route on /photos/12 and 405s.

Example · php
<?php

// routes/web.php
Route::get('/photos/{photo}/edit', [PhotoController::class, 'edit'])->name('photos.edit');
Route::put('/photos/{photo}', [PhotoController::class, 'update'])->name('photos.update');

// resources/views/photos/edit.blade.php
// <form method="POST" action="{{ route('photos.update', $photo) }}">
//     @csrf
//     @method('PUT')
//     <input name="caption" value="{{ $photo->caption }}">
// </form>
//
// @method('PUT') renders:
// <input type="hidden" name="_method" value="PUT">

echo route('photos.update', ['photo' => 12]);
// http://example.com/photos/12

Full replacement with route model binding

Because the {photo} segment matches the type-hinted $photo argument, Laravel resolves the model and returns a 404 automatically if no such row exists — the controller never sees a missing id. The validation rules mark every field required, which is what makes this a PUT rather than a PATCH.

Example · php
<?php

// routes/web.php
Route::put('/photos/{photo}', [PhotoController::class, 'update'])->name('photos.update');

// app/Http/Controllers/PhotoController.php
public function update(Request $request, Photo $photo): RedirectResponse
{
    // PUT means "replace": every field is expected, missing ones are reset.
    $data = $request->validate([
        'caption' => 'required|string|max:255',
        'alt'     => 'nullable|string|max:255',
        'public'  => 'required|boolean',
    ]);

    $photo->update($data);

    return redirect()->route('photos.show', $photo);
}

echo route('photos.update', ['photo' => 12]);
// http://example.com/photos/12

Discussion

  • Be the first to comment on this lesson.