Reader Stacks

Conditional Validation Rules in Laravel

requiredIf, requiredUnless, sometimes, and a full closure-based rule all handle a field that should only be validated under a specific condition.

A form field that should only be required (or validated a certain way) depending on another field's value is a common requirement — Laravel offers several built-in conditional rule helpers that cover most of these cases without needing to write custom validation logic from scratch.

requiredIf: required only when another field equals a specific value

$request->validate([
    'account_type' => 'required|in:personal,business',
    'company_name' => Rule::requiredIf($request->account_type === 'business'),
]);

requiredUnless: required unless another field equals a specific value

$request->validate([
    'shipping_address' => Rule::requiredUnless('delivery_method', 'pickup'),
]);

requiredWith and requiredWithout

$request->validate([
    'password_confirmation' => 'required_with:password',
    'guest_email' => 'required_without:user_id',
]);

required_with makes a field required only if another specific field is also present in the request — required_without is the inverse, requiring a field only when another one is absent, useful for something like a guest checkout flow where either a logged-in user ID or a guest email is needed, but not necessarily both.

Using sometimes() for entirely conditional rule sets

$validator = Validator::make($request->all(), [
    'email' => 'required|email',
]);

$validator->sometimes('promo_code', 'required|string', function ($input) {
    return $input->wants_discount === true;
});

sometimes() is the more flexible option when the condition itself is more complex than a simple field comparison — the closure receives the full input and can implement essentially any logic to decide whether the rule should apply at all.

A fully custom conditional rule with a closure

$request->validate([
    'discount_code' => [
        function ($attribute, $value, $fail) use ($request) {
            if ($request->cart_total < 50 && ! empty($value)) {
                $fail('Discount codes can only be used on orders over $50.');
            }
        },
    ],
]);

A closure-based rule is the escape hatch for validation logic that doesn't fit any of the built-in conditional helpers — it receives the field's value directly and calls $fail() with a custom message when the condition it implements isn't met.

Combining conditional rules in a Form Request class

class OrderRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'account_type' => 'required|in:personal,business',
            'company_name' => Rule::requiredIf($this->account_type === 'business'),
            'tax_id' => Rule::requiredIf($this->account_type === 'business'),
        ];
    }
}

Inside a Form Request class, $this refers to the request itself, so $this->account_type reads the submitted value the same way $request->account_type would in a controller — the conditional rule logic works identically whether it lives inline in a controller or extracted into its own Form Request class.

Why conditional rules are worth using over manual if/else validation

Expressing the condition directly in the rules array (rather than manually branching with if/else and calling Validator::make() with different rule sets in each branch) keeps every field's full set of conditions visible in one place, making the validation logic easier to read and modify later than logic scattered across separate conditional branches.