Laravel’s required_if validation rule makes a field required only when another field equals a specific value. Instead of manually checking conditions in your controller before calling validate(), you declare the dependency directly in your rules array. Laravel handles the rest. The rule comes in four forms: a rule string, Rule::requiredIf() with a boolean, Rule::requiredIf() with a closure, and the newer Rule::when() — each suited to a different level of complexity.
This guide covers all four, with a full Form Request example and the one gotcha that breaks most people’s first attempt.
:::note[TL;DR]
'required_if:field,value'is the simplest form — use it for static, single-value conditionsRule::requiredIf($bool)accepts a pre-computed boolean for conditions that need a method callRule::requiredIf(fn() => ...)accepts a closure for multi-condition or lazy-evaluated logicRule::when($condition, $trueRules, $falseRules)is the cleanest option when you need to define both rule sets- Always pair
required_ifwithnullableon the counterpart field to avoid unexpected validation failures :::
What does required_if actually do?
required_if tells the validator: “this field is mandatory, but only when another field has this specific value.” Without it, you’d write something like this in your controller:
// The manual approach — messy and not reusable
if ($request->input('contact_method') === 'phone') {
$request->validate(['phone' => 'required|string']);
} else {
$request->validate(['phone' => 'nullable|string']);
}
That’s two separate validate() calls, conditional logic bleeding into your controller, and nothing you can move to a Form Request. required_if collapses all of that into one rule.
The scenario: You’re building a checkout form. If the user picks “SMS” as their notification preference, their phone number is required. If they pick “email”, it isn’t. You could add an
ifblock in your controller and call it done. Then product adds a third option (“push notification”), and now you’ve got three branches. Usingrequired_ifin a Form Request means you change one line, not threeifblocks.
Method 1 — Rule string: when is it enough?
The string form 'required_if:field,value' is the right choice when the condition is a static string comparison. No imports, no extra syntax.
The validator checks whether the named field equals the given value. If it does, the current field is required.
// 'phone' is required when 'contact_method' equals 'phone'
'phone' => 'required_if:contact_method,phone',
You can pass multiple values as a comma-separated list. The field becomes required when the other field matches any of them:
// Required when contact_method is 'phone' OR 'sms'
'phone' => 'required_if:contact_method,phone,sms',
That’s the full power of the string form. Anything more complex — a method call, a comparison between two request values, an external check — needs one of the Rule:: forms below.
Method 2 — Rule::requiredIf() with a boolean: when you need a method call
Rule::requiredIf() accepts a boolean expression. The boolean is evaluated immediately — before the validator processes the field — so it’s suitable for conditions that need a method call or a property lookup.
The rule is in Illuminate\Validation\Rule, so import it at the top of your file:
use Illuminate\Validation\Rule;
// Billing address is required when the user is on a paid plan
'billing_address' => Rule::requiredIf($request->user()->isPaying()),
The isPaying() call runs once, returns true or false, and the validator treats the result as a fixed condition. This is cleaner than computing the boolean before validate() and threading it into a rule string.
The scenario: Your app has free and paid tiers. Paid users must fill in a billing address during setup. You could check
$user->isPaying()in the controller and conditionally add the rule. But six months later someone adds another field with the same condition. Now that check lives in two places. PuttingRule::requiredIf($request->user()->isPaying())directly in the Form Request keeps the logic in one file.
Method 3 — Rule::requiredIf() with a closure: for complex or lazy-evaluated conditions
When your condition involves multiple inputs, a closure is the right choice. The closure is evaluated lazily — only when the validator actually reaches that field — which matters if you’re doing something expensive inside it.
use Illuminate\Validation\Rule;
// Required only when BOTH conditions are true
'phone' => Rule::requiredIf(function () use ($request) {
return $request->input('contact_method') === 'phone'
&& $request->input('country') === 'US';
}),
The closure receives no arguments by default — you capture what you need via use. Inside a Form Request, use $this instead of $request:
'phone' => Rule::requiredIf(function () {
return $this->input('contact_method') === 'phone'
&& $this->input('country') === 'US';
}),
Method 4 — Rule::when(): define both rule sets in one place
Rule::when() is the cleanest option when you want to define what happens in both the truthy and falsy case. It was introduced in Laravel 9 and is fully supported in Laravel 10, 11, and 12.
use Illuminate\Validation\Rule;
'phone' => Rule::when(
$request->contact_method === 'phone',
['required', 'string', 'min:10'], // rules when condition is true
['nullable'] // rules when condition is false
),
The third argument (the falsy rules) is optional. If you omit it, the field has no rules when the condition is false — which is usually the same as passing ['nullable'], but being explicit is safer.
Rule::when() reads more clearly than a closure for simple two-branch logic, and it keeps your rules array looking uniform.
What does a full Form Request look like?
Here’s a realistic ContactRequest that combines multiple approaches in the same rules array. The contact_method field drives the requirements for both email and phone.
This Form Request uses the string form for email (simple static condition) and a closure for phone (to show the pattern — in practice, the string form works here too):
// app/Http/Requests/ContactRequest.php
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class ContactRequest extends FormRequest
{
public function rules(): array
{
return [
'contact_method' => ['required', 'in:email,phone'],
'email' => ['required_if:contact_method,email', 'nullable', 'email'],
'phone' => Rule::requiredIf(function () {
return $this->input('contact_method') === 'phone';
}),
];
}
}
Note the 'nullable' on the email field. That’s the gotcha — see below.
:::warning
In Laravel 11+, Rule::requiredIf() and Rule::when() are in Illuminate\Validation\Rule. The class-string shorthand 'required_if:field,value' still works unchanged and hasn’t been deprecated. Both approaches are fully supported in Laravel 10, 11, and 12. If you’re on Laravel 8 or 9, all four methods shown here are also available — Rule::when() was added in Laravel 9.
:::
What’s the nullable gotcha?
When a user selects email as their contact method, the phone field is not submitted (or submitted as an empty string). Without nullable on the phone rule, Laravel’s sometimes implicit rule won’t kick in the way you expect — depending on your validation pipeline, an absent phone field can fail other checks.
More importantly: if you have required_if:contact_method,phone on phone but no nullable, the field is effectively “required always” from Laravel’s perspective when contact_method is email. Adding nullable explicitly tells the validator that an absent or null phone is acceptable when the condition isn’t met.
// Without nullable — can cause unexpected failures
'phone' => 'required_if:contact_method,phone',
// Correct — nullable makes the non-required case explicit
'phone' => ['required_if:contact_method,phone', 'nullable', 'string'],
Always pair required_if with nullable (or sometimes) on both the dependent and the counterpart fields.
For working with date-based validation rules alongside conditional validation, see check for past date in Laravel.
Summary
'required_if:field,value'is the simplest form; handles static string comparisons and multiple valuesRule::requiredIf($bool)evaluates immediately — use it for method calls or property checksRule::requiredIf(fn() => ...)evaluates lazily — use it for multi-condition logic using other request inputsRule::when($condition, $trueRules, $falseRules)is the cleanest form when you want to define both branches- Always add
nullableto fields controlled byrequired_ifto prevent unexpected validation failures
FAQ
Can I use required_if with numeric comparisons?
The string form only does strict equality checks. For numeric comparisons, use required_if:age,18 for exact matches, or switch to Rule::requiredIf() with a closure: Rule::requiredIf(fn() => $this->input('age') >= 18).
What’s the difference between required_if and required_unless?
required_if:field,value makes a field required when another field equals the value. required_unless:field,value does the opposite — it makes a field required when the other field does NOT equal the value. Both accept multiple values in the string form.
Does Rule::when() work inside $request->validate() directly, or only in Form Requests?
Both. Rule::when() works wherever you build a rules array — inside $request->validate(['field' => Rule::when(...)]), a Validator::make() call, or a Form Request’s rules() method. The syntax is identical.
Can I nest required_if rules? For example, required when field A equals X and field B equals Y?
The string form doesn’t support AND conditions — it’s OR across multiple values. For AND logic, use Rule::requiredIf() with a closure and check both conditions inside it.
What happens if the field named in required_if doesn’t exist in the request at all?
Laravel treats the missing field’s value as null. If your rule is required_if:contact_method,phone, and contact_method isn’t in the request, Laravel sees null !== 'phone' and the current field is not required. This is usually the correct behavior, but worth knowing if you’re debugging missing-field edge cases.
What to Read Next
- Check for Past Date in Laravel
- Using firstOrCreate in Laravel Eloquent
- Using whereDate in Laravel Eloquent