Built-in validation rules such as required, email, or max are not enough for most real-word applications. Your requirements might need custom business logic such as checking if a username contains a certain word, or if a user has a specific role.

Laravel gives you three main ways to define custom validation:

Closure-Based Custom Rules (Inline in Controller)

This is the simplest way to define a custom rule using a closure (anonymous function) directly in your validation array.

Example: Disallow usernames containing “admin”
PHP:

$request->validate([ 'username' => [ 'required', function ($attribute, $value, $fail) { if (stripos($value, 'admin') !== false) { $fail('The username cannot contain the word "admin".'); } }, ],
]);

When to use: Small, one-time rules specific to a form.

Custom Rule Class (Reusable Rules)

Use Laravel’s artisan command to create a custom rule class.

Step 1: Create the rule

Bash:

php artisan make:rule Uppercase

Step 2: Define logic in the rule class

PHP:

// app/Rules/Uppercase.php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Uppercase implements Rule
{ public function passes($attribute, $value) { return strtoupper($value) === $value; } public function message() { return 'The :attribute must be in uppercase.'; }
}

Step 3: Use the rule in a controller

PHP:

use App\Rules\Uppercase;
$request->validate([ 'title' => ['required', new Uppercase],
]);

When to use: When the rule will be reused across different forms or logic is too complex for closures.

Extending the Validator (Custom Rule Name)

You can register your own validation rule globally using Laravel’s Validator::extend method (typically in a service provider).

Step 1: Extend Validator

PHP:

use Illuminate\Support\Facades\Validator;
public function boot()
{ Validator::extend('foo', function ($attribute, $value, $parameters, $validator) { return $value === 'foo'; });
}

Step 2: Use the new rule name

PHP:

$request->validate([ 'code' => 'required|foo',
]);

Optional: Custom message

PHP:

// resources/lang/en/validation.php
'foo' => 'The :attribute must be "foo".',

When to use: When you want clean, named rules you can apply like built-in rules.

Customizing Error Messages (All Methods)

You can customize error messages like this:

PHP:

$request->validate([ 'username' => 'required|min:5',
], [ 'username.required' => 'Please enter your username.', 'username.min' => 'Your username must be at least :min characters long.',
]);

This helps you keep messages user-friendly and in plain language.

Example Use Case: Validating Age Must Be Over 18

Custom Rule Class

Bash:

php artisan make:rule AgeOver18

Rule Logic

PHP:

public function passes($attribute, $value)
{ return Carbon\Carbon::parse($value)->age >= 18;
}
public function message()
{ return 'You must be at least 18 years old.';
}

Usage

PHP:

$request->validate([ 'dob' => ['required', 'date', new AgeOver18],
]);

Summary Table

MethodUse WhenReusabilityComplexity
Closure-basedQuick one-off logicNoSimple
Custom Rule ClassRule used in multiple placesYesMedium
Validator ExtensionWant named rulesYesAdvanced

Pro Tips

  • Group multiple custom rules in one file for better organization.
  • Reuse custom rule classes to follow DRY principles.
  • Store messages in resources/lang for localization support.