In Laravel validation, what is the difference between the nullable, sometimes and present rules, and when do you need each?
answer
- absent key vs key sent as null
- ConvertEmptyStringsToNull turns '' into null
- nullable: null skips the other rules
- sometimes: validate only if the key exists
- present: key must exist, may be empty
basics
~20 snullable lets a present field be null and then skips its other rules; sometimes runs a field's rules only when the key exists in the input; present requires the key to exist but accepts an empty value.
solid answer
~40 sLaravel's validator skips ordinary rules for a key that is absent or an empty string, but a key sent as `null` is present, so `string` or `date` run and fail. Because the default middleware stack includes `TrimStrings` and `ConvertEmptyStringsToNull`, an empty form field arrives as `null` — hence `nullable` on optional fields. `sometimes` works on presence: if the key is missing, none of the field's rules run, including `required`, so `['sometimes', 'required', 'string']` means "optional, but not blank when sent" — typical for a PATCH. `present` is an implicit rule that fails when the key is missing yet accepts `null` or an empty value, useful when the client must send the field even if it is empty.
code
php · 12 lines<?php
use Illuminate\Validation\Rule;
$rules = [
'username' => [
'sometimes', 'required', 'string', 'max:30',
Rule::unique('users', 'username')->ignore($user),
],
'bio' => ['sometimes', 'nullable', 'string', 'max:300'],
'interests' => ['present', 'array'],
];go deeper
Remember to add nullable to optional form fields, because empty inputs arrive as null.
Explain absent versus null, implicit versus ordinary rules, and why sometimes|required suits PATCH endpoints.
Design API contracts where 'not sent' and 'sent as null' mean different things, and choose present, filled or missing accordingly.
Standardise how partial updates and field clearing are expressed across the API so clients never guess.
## Two different questions: is the key there, and is it null? Laravel's validator distinguishes three states for a field: 1. **Absent** — the key is not in the input at all. 2. **Present but empty** — the key exists with `null`, an empty string, or an empty array. 3. **Present with a value**. Rules come in two kinds: - **Implicit rules** (`required`, `required_if`, `present`, `filled`, `accepted`, `missing`...) always run, even for absent or empty fields. - **Ordinary rules** (`string`, `email`, `max`, `date`...) are **skipped** when the key is absent or holds an empty string, but they **do run** when the key holds `null`. That last point is the source of most confusion. ## Why null shows up so often A new Laravel app's global middleware stack includes `TrimStrings` and `ConvertEmptyStringsToNull`. An HTML input left blank is posted as `""`, trimmed, and converted to `null` before validation. So an optional "bio" field that the user leaves empty reaches the validator as **present and null**, and `['string', 'max:300']` fails with "The bio field must be a string." ## nullable `nullable` says "null is acceptable". When the value is `null`, the validator skips the field's ordinary rules. Implicit rules still run, so `['nullable', 'required']` still fails on null. - Use on every optional field of a browser form. - In `validated()`, a nullable field sent as null appears with the value `null`. ## sometimes `sometimes` says "only validate this field if the key is present". If the key is absent, **every** rule for that field is skipped — including implicit ones like `required`. - `['sometimes', 'required', 'string', 'max:30']` → may be omitted; if sent, must not be empty. - Typical for PATCH endpoints where clients send only the fields they change. - Without `sometimes`, `required` on a PATCH forces the client to resend everything. (`Validator::sometimes()`, the method that adds rules under a closure condition, is a different feature with the same word.) ## present and filled - **`present`** — an implicit rule that passes whenever the key exists, whatever the value. Use it when the contract says "always send this key, even as null or an empty list". - **`filled`** — if the key exists, it must not be empty; if absent, it passes. Close to `sometimes|required`. - **`missing`** — the opposite of `present`: the key must not be sent. ## Behaviour table Rules on `bio` and what happens for each input: | Rules | key absent | `null` | `"hello"` | |---|---|---|---| | `string` | passes (skipped) | **fails** | passes | | `nullable, string` | passes | passes | passes | | `required, string` | fails | fails | passes | | `sometimes, required, string` | passes (skipped) | fails | passes | | `present` | fails | passes | passes | | `filled` | passes | fails | passes | ## Choosing for the profile-edit scenario - `username` on a full-form PUT: `['required', 'string', 'max:30', ...]`. - `username` on a PATCH: `['sometimes', 'required', 'string', 'max:30', ...]` — optional, never blank. - `bio`: `['nullable', 'string', 'max:300']` — may be cleared. - `interests`: `['present', 'array']` if the client must always send the list, even empty, so "not sent" is not mistaken for "cleared". ## Traps - Calling the validator directly on an array (not an HTTP request) skips the middleware, so an empty string stays `""` and ordinary rules are skipped for it — behaviour differs from the same rules on a form post. - `nullable` does not make a field optional in the sense of "may be absent" — an absent key was already fine for ordinary rules; `nullable` is about the explicit null. - `sometimes` placed on a field that the browser always sends (every text input is sent, even empty) has no effect; the key is always present. - Unchecked checkboxes are **not** sent at all, so on a checkbox field the key really is absent — the one browser case where `sometimes`, `present` and `required` behave very differently. ## How to answer in an interview Lead with the two axes — presence of the key, and null-ness of the value — then place each rule on them: `sometimes` acts on presence, `nullable` on null, `present` demands the key. Mentioning `ConvertEmptyStringsToNull` shows you know why `nullable` appears on nearly every optional field in real Laravel code.
- Why does ['string'] pass when the key is missing but fail when it is sent as null?The validator only runs ordinary rules when the key is present (and not an empty string) or the rule is implicit. A missing key is not present, so `string` is skipped; a `null` value is present, so `string` runs and fails unless `nullable` is also set.
- Does sometimes help on a normal HTML form text input?Rarely. Browsers submit every text input, even when blank, so the key is always present and `sometimes` never skips anything. It matters for JSON APIs and PATCH requests where clients omit keys, and for checkboxes, which are not sent when unchecked.
Think of a hotel check-in form: sometimes is "only look at the parking section if they filled in that page at all", nullable is "a blank licence plate is fine", and present is "the parking page must be handed in, even if blank".
saying these in an interview costs you the question
- Without nullable, an omitted optional key fails its string rule
- sometimes skips ordinary rules but still enforces required
- Ordinary rules are skipped when a field is sent as null
- present fails when the value is null
- ConvertEmptyStringsToNull is opt-in and off by default