Clean Form Validation in Laravel

Validation is your application's first line of defense: it ensures incoming data matches your expectations before it ever touches the database. Laravel ships with a very complete v...

Clean Form Validation in Laravel

Validation is your application's first line of defense: it ensures incoming data matches your expectations before it ever touches the database. Laravel ships with a very complete validation system, yet many developers pile everything into the controller until it becomes a mess. This article shows how to validate forms cleanly in Laravel 10/11 — from the simplest approach to custom rules.

1. Inline Validation with validate()

The fastest way: call $request->validate() directly in the controller. On failure, Laravel automatically redirects the user back with the error messages and old input.

public function store(Request $request)
{
    $data = $request->validate([
        'name'  => 'required|string|max:255',
        'email' => 'required|email|unique:users,email',
        'age'   => 'nullable|integer|min:17',
    ]);

    User::create($data);

    return back()->with('success', 'Saved.');
}

The return value of validate() contains only the fields that passed the rules — safe to pass straight into create().

2. Commonly Used Validation Rules

  • required / nullable — required or allowed to be empty.
  • email, numeric, integer, string, boolean — data types.
  • min:3 / max:255 — string length or numeric value.
  • unique:users,email / exists:categories,id — database checks.
  • confirmed — great for passwords (needs a password_confirmation field).
  • in:draft,published — value must be one of a list.

3. Form Requests for Clean Controllers

As rules grow, move them into a Form Request class so the controller stays lean:

php artisan make:request StoreArticleRequest

Fill in the authorize() and rules() methods:

public function authorize(): bool
{
    return true; // replace with permission logic if needed
}

public function rules(): array
{
    return [
        'title'    => 'required|string|max:150',
        'body'     => 'required|string',
        'status'   => 'required|in:draft,published',
        'tags'     => 'array',
        'tags.*'   => 'string|max:30',
    ];
}

Then simply type-hint it in the controller — validation runs automatically before the method executes:

public function store(StoreArticleRequest $request)
{
    Article::create($request->validated());
    return redirect()->route('articles.index');
}

4. Custom Messages and Attribute Names

The default error messages are in English. Override them with the messages() and attributes() methods in the Form Request:

public function messages(): array
{
    return [
        'title.required' => 'The title is required.',
        'title.max'      => 'The title may not exceed 150 characters.',
    ];
}

public function attributes(): array
{
    return [
        'title' => 'article title',
    ];
}

With attributes(), a generic message like "The title field is required" becomes "The article title field is required" — handy for the :attribute placeholder.

5. Custom Validation Rules

For unique logic, create your own rule:

php artisan make:rule Uppercase
public function validate(string $attribute, mixed $value, Closure $fail): void
{
    if (strtoupper($value) !== $value) {
        $fail('The :attribute must be uppercase.');
    }
}

Use it alongside built-in rules:

'code' => ['required', new Uppercase],

For one-off validation, you can also write a closure inline:

'slug' => [
    'required',
    function ($attribute, $value, $fail) {
        if (str_contains($value, ' ')) {
            $fail('The slug may not contain spaces.');
        }
    },
],

6. Displaying Errors in Blade

Laravel stores errors in an $errors variable that is always available in every view. Display them per field and preserve old input with old():

<input type="text" name="title" value="{{ old('title') }}">

@error('title')
    <span class="text-red-500">{{ $message }}</span>
@enderror

To show all errors at the top of the form:

@if ($errors->any())
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
@endif

7. Validating Arrays and Files

Use dot notation with * to validate each element of an array, and file rules for uploads:

$request->validate([
    'items'        => 'required|array|min:1',
    'items.*.name' => 'required|string',
    'items.*.qty'  => 'required|integer|min:1',
    'avatar'       => 'required|image|mimes:jpg,png|max:2048',
]);

The max:2048 rule on a file is measured in kilobytes, so the example above caps the image at 2 MB.

Conclusion

Start with inline validate() for simple forms, then move to Form Requests as rules grow. Override messages to be user-friendly, and build custom rules for special needs. With this approach your validation stays centralized, easy to test, and your controllers stay clean.

Yudhi
Written by
Yudhi
Founder & Lead Developer, GudangCode

Yudhi is the founder of GudangCode and a Laravel developer who has built dozens of ready-to-use business information systems — from POS and HRIS to management apps. He writes guides and articles on GudangCode to help Indonesian developers run, understand, and deploy Laravel source code correctly.

LaravelPHPMySQLSistem Informasi Bisnis See all articles by Yudhi
Want the full source code & apps?

Sign up free to download ready-to-use business applications, information systems, and Laravel source code.

Sign Up Free & Download
Validasi Form Laravel Programming & Laravel
Share this article
Back to Blog
📚 Free Learning Hub

Learn Coding for Free at DhieCoderWeb

Explore Laravel, PHP, JavaScript tutorials, source code, web development guides, and practical programming tips.

DhieCoderWeb
100+
Tutorials
Free
Learning
SEO
Tips
Visit Dhiecoderweb.com →

Get Full Access Now!

Join our membership and unlock exclusive access to all premium features. Fast, easy, and ready to use instantly.

Join Membership Now
Tim Support
Online
Isi data dulu untuk mulai chat:
Beri rating & testimoni sebelum menutup:
Live chat by gudangcode.com