To validate a form in Laravel 13, create a Form Request with php artisan make:request, put your rules in its rules() method, type-hint it in the controller, and read clean data with $request->validated(). Laravel then redirects back with errors automatically when validation fails.
This tutorial builds a complete registration-style form with rules, error display, old input, a unique rule and a feature test.
What do I need first?
- Laravel 13 (current stable at the time of writing) with a supported PHP version.
- A
userstable, or any table you want to save into.
Should I validate in the controller or a Form Request?
Both work. Inline $request->validate([...]) is fine for two or three rules. A Form Request is better when rules grow, when you want custom messages, or when authorization belongs with the input rules. It keeps controllers short and rules reusable.
How do I create the Form Request?
php artisan make:request StoreMemberRequest<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StoreMemberRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:100'],
'email' => ['required', 'email:rfc', 'max:255', Rule::unique('users', 'email')],
'age' => ['nullable', 'integer', 'between:18,100'],
'website' => ['nullable', 'url'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
'terms' => ['accepted'],
];
}
}authorize() must return true for the request to proceed. Return false and Laravel sends a 403 response before the controller runs. Use it for permission checks, for example with a policy.
The confirmed rule expects a matching password_confirmation field. The accepted rule passes for values such as on, yes, 1 and true.
How do I use it in the controller?
use App\Http\Requests\StoreMemberRequest;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
public function store(StoreMemberRequest $request)
{
$data = $request->validated();
User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
return redirect()->route('members.index')
->with('status', 'Member created.');
}Only fields that have a rule appear in validated(). That protects you from mass assignment of unexpected input.
How do I build the form in Blade?
<form method="POST" action="{{ route('members.store') }}">
@csrf
<label for="name">Name</label>
<input id="name" name="name" value="{{ old('name') }}">
@error('name') <p class="error">{{ $message }}</p> @enderror
<label for="email">Email</label>
<input id="email" type="email" name="email" value="{{ old('email') }}">
@error('email') <p class="error">{{ $message }}</p> @enderror
<label for="password">Password</label>
<input id="password" type="password" name="password">
@error('password') <p class="error">{{ $message }}</p> @enderror
<label for="password_confirmation">Confirm password</label>
<input id="password_confirmation" type="password" name="password_confirmation">
<label><input type="checkbox" name="terms"> I accept the terms</label>
@error('terms') <p class="error">{{ $message }}</p> @enderror
<button type="submit">Save</button>
</form>old('name') refills the field after a failed attempt. Never refill password fields. Laravel does not flash them by default.
How do I ignore the current record in a unique rule?
On an edit form, the email already exists for this record, so the plain unique rule fails. Ignore the current id.
'email' => [
'required',
'email',
Rule::unique('users', 'email')->ignore($this->route('user')),
],How do I add a check that depends on several fields?
Use the after() method of the Form Request. It returns callables that receive the validator.
use Illuminate\Validation\Validator;
public function after(): array
{
return [
function (Validator $validator) {
if ($this->input('age') && ! $this->filled('guardian') && $this->integer('age') < 21) {
$validator->errors()->add('guardian', 'A guardian name is required under 21.');
}
},
];
}How do I prepare input before validating?
Override prepareForValidation() to trim or normalise values, for example to lower-case the email.
protected function prepareForValidation(): void
{
$this->merge([
'email' => strtolower(trim((string) $this->input('email'))),
]);
}What are the common mistakes?
- Forgetting
@csrf. The form returns a 419 error. - Returning false from authorize(). You get a 403 and no validation messages.
- Using
$request->all()after validation. It includes unvalidated input. Usevalidated(). - Wrong confirmation name. The field must be named
password_confirmation. - Missing
enctypeon file forms. Addenctype="multipart/form-data"when uploading.
How do I test the form?
public function test_member_requires_valid_email(): void
{
$response = $this->post('/members', [
'name' => 'Sara',
'email' => 'not-an-email',
]);
$response->assertSessionHasErrors(['email', 'password', 'terms']);
}
public function test_member_can_be_created(): void
{
$this->post('/members', [
'name' => 'Sara',
'email' => 'sara@example.com',
'password' => 'long-enough-1',
'password_confirmation' => 'long-enough-1',
'terms' => 'on',
])->assertRedirect(route('members.index'));
$this->assertDatabaseHas('users', ['email' => 'sara@example.com']);
}FAQ
Where do validation errors go for API requests?
If the request expects JSON, Laravel returns a 422 response with an errors object instead of redirecting.
Can I stop at the first failing rule?
Yes. Add the bail rule at the start of a field's rules.
How do I change the messages?
Add a messages() method to the Form Request that returns an array of field.rule keys.



