Laravel nullable exists validation is how you validate a foreign-key field that is optional — the value must exist in another table when provided, but null and missing values should still pass. The one-liner is 'nullable|exists:table,column', but there are three rule combinations (nullable, sometimes, present) that behave differently depending on whether the key is absent from the payload, empty-string, or null. This guide covers each, when to reach for which, and the empty-string trap that catches most developers.
Last verified: 2026-04-23 on Laravel 11 with PHP 8.3. Originally published 2023-01-30 & 2023-10-10, merged, rewritten, and updated 2026-04-23.
TL;DR
Use 'vehicle_model_id' => 'nullable|exists:vehicle_models,id'. The nullable rule tells Laravel to treat null as valid; if a non-null value is sent, exists checks the database. Add sometimes in front if the key itself may be missing from the payload.
The canonical fix: nullable|exists
The most common shape of this problem: a form has an optional foreign-key field — a vehicle_model_id on a vehicle record, a category_id on a product, a parent_id on a comment. The column is nullable in the database, and the request payload may send null (or omit the key). Without nullable, Laravel’s exists rule will run against null and fail with “The selected vehicle_model_id is invalid.”
The fix is a single extra rule:
$request->validate([
'vehicle_model_id' => 'nullable|exists:vehicle_models,id',
]);
Rule order doesn’t affect behavior here — Laravel evaluates all rules — but the convention is to put nullable first because it’s the “gate”: if the value is null, the validator short-circuits to success and never hits the database. That matters on high-traffic endpoints where skipping an unnecessary query per optional field adds up.
When nullable isn’t enough: sometimes
nullable only whitelists the literal PHP null. If the request doesn’t include the key at all — a partial-update API where the client omits unchanged fields — Laravel still treats absence differently from null. For that case, reach for sometimes:
$request->validate([
'vehicle_model_id' => 'sometimes|exists:vehicle_models,id',
]);
sometimes means “only run subsequent rules if this field is present in the request.” If the client sends {"make": "Toyota"} without a vehicle_model_id key, the validator skips the exists check entirely. If the client sends {"vehicle_model_id": null}, sometimes sees it as present and the exists rule runs against null — which fails. For the “optional and nullable” case, stack both:
$request->validate([
'vehicle_model_id' => 'sometimes|nullable|exists:vehicle_models,id',
]);

Strict APIs: present|nullable|exists
The opposite of sometimes is present. present requires the key to exist in the payload but places no requirement on its value. Pair it with nullable and exists to say “the field must be sent — but its value can be null or a valid foreign key”:
$request->validate([
'vehicle_model_id' => 'present|nullable|exists:vehicle_models,id',
]);
This is useful for strict API contracts where a missing key is a client bug — typically when the frontend is supposed to clear the value to null explicitly rather than omit it. For loose contracts (partial updates, optional UI fields), stick with sometimes.
The empty-string trap
HTML forms send empty <input> values as the empty string "", not null. nullable does not whitelist empty strings — only the literal PHP null. So this still fails:
// Request payload: { "vehicle_model_id": "" }
$request->validate([
'vehicle_model_id' => 'nullable|exists:vehicle_models,id',
]);
// "The selected vehicle_model_id is invalid."
Laravel ships with a middleware that fixes this for standard form requests: Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull is registered in the web and api middleware groups by default. It rewrites empty strings to null before your controller ever sees the payload, and nullable then handles them correctly. If you’ve removed that middleware (or you’re receiving data through a channel that bypasses it — queue jobs, console commands, direct model creation), you have two options:
- Re-register
ConvertEmptyStringsToNullfor the relevant middleware group inbootstrap/app.php. - Add
filledalongsidenullable:'nullable|filled|exists:...'—filledskips the rule when the field is present but empty.
Quick reference: which rule when
| Payload | nullable | sometimes | present |
|---|---|---|---|
| Key missing | fails | skips | fails |
Value is null | passes | runs exists (fails) | runs exists (fails) |
Value is "" | runs exists (fails) | runs exists (fails) | runs exists (fails) |
| Value is valid FK | passes | passes | passes |
Read down each column: pick nullable when the client always sends the key but the value may be null, sometimes when the key itself may be absent, present when the key is mandatory but a null value is acceptable.
Frequently asked questions
'field' => 'nullable|exists:table,column'. Laravel’s nullable rule tells the validator to treat null and missing values as valid; if a value is present, the exists rule then runs against the database. This is the one-line fix that covers the typical “foreign key that might be null” case.
sometimes instead of nullable? Use sometimes when the field might be absent from the request entirely (not sent as a key at all). nullable only whitelists null; if the request never includes the key, nullable on its own still requires you to also allow that. sometimes|exists:table,column means “only run validation if the key is present.” Stack them for the safest variant: sometimes|nullable|exists:table,column.
nullable allow empty strings? No. nullable only whitelists the literal PHP null. An empty string "" is still treated as a present value, so exists would run and fail. If your frontend sends empty strings, either coerce them to null in middleware (ConvertEmptyStringsToNull in app/Http/Kernel.php is Laravel’s default) or add the rule 'nullable|filled|exists:...' so the validator skips truly empty input.
present|exists|nullable do? present requires the key to exist in the request payload but allows its value to be anything, including null. Combined with exists and nullable, it means “the field must be sent, but its value can be null or a valid foreign key.” Useful for strict API contracts where a missing key is a client bug even when the value is optional.
exists rule still fail on a nullable field? Two common causes. First, the value being sent is an empty string, not null — see the previous answer. Second, the order of rules matters when you read errors but not when validation runs; Laravel evaluates all rules, so nullable always short-circuits for null regardless of position. If it’s still failing, dd($request->all()) and check the actual payload type.
Related guides
- How to Check if Exists in the Database with the Laravel Validator — the base
existsrule, unique counterpart, and custom table/column targeting. - How to Check if a Record Exists in Laravel — querying existence in Eloquent (outside the validator).
- How to Add Foreign Keys in Laravel Migration — define the schema that
existsvalidates against. - How to Install Laravel on Ubuntu — set up Laravel 11 and Artisan before validating anything.
References
Official Laravel validation docs (nullable, sometimes, present, exists, filled): laravel.com/docs/validation.