min
Enforces a minimum size: characters, numeric value, array count or file kilobytes.
min:valueParameters
| Parameter | Type | Description |
|---|---|---|
$value | int|float | The minimum size. Interpreted as characters for strings, the numeric value for numbers, the element count for arrays, or kilobytes for files. |
Errors
Nothing on its own; a failure surfaces as Illuminate\Validation\ValidationException when run through validate() or a form request.
The field under validation must have a minimum value. Strings, numerics, arrays and files are evaluated in the same fashion as the size rule — which is the whole story and the whole problem, because "size" means four different things:
- String — the number of characters.
- Numeric — the value itself, but only when the attribute also carries the
numericorintegerrule. - Array — the element count.
- File — the file size in kilobytes.
The trap
Every value in an HTTP request arrives as a string. Without numeric or integer alongside it, 'age' => 'min:18' measures the length of "20" — two characters — and fails. The fix is always 'age' => 'integer|min:18'. This single omission accounts for most confused reports about min, and it fails in the worst way: "100" passes because it is three characters long.
Digits versus magnitude
If you want "at least four digits" rather than "at least 4", the rule is min_digits, not min.
min is not implicit — an absent or empty field skips it entirely, so pair it with required.
Example
<?php
use Illuminate\Support\Facades\Validator;
$data = ['age' => '20']; // as it arrives from a form post
// No numeric rule: "20" is measured as a 2-character string.
var_dump(Validator::make($data, ['age' => 'min:18'])->passes());
// With integer, 20 is compared as a number.
var_dump(Validator::make($data, ['age' => 'integer|min:18'])->passes());
// bool(false)
// bool(true)When to use it
- Requiring a password of at least 8 characters.
- Enforcing a minimum order quantity on a numeric input.
- Rejecting an empty multi-select by demanding at least one chosen option.
- Refusing suspiciously tiny uploads such as a zero-byte avatar.
Frequently asked questions
Why does min:18 fail on the value 20?
Because "20" arrived as a string and `min` counted its two characters. Add `integer` or `numeric` before `min` so the value is compared as a number: `'age' => 'integer|min:18'`. Without a numeric companion rule, `min` always measures string length.
Is min on a file in bytes or kilobytes?
Kilobytes. `min:1` means one kilobyte and `max:2048` means two megabytes. This matches the `size` rule's behaviour for files, so a rule like `min:1024` demands a one-megabyte file, not a one-kilobyte one.
Does min require the field to be present?
No — `min` is not an implicit rule, so an absent or empty field skips it entirely and validation passes. Combine it with `required` (or `sometimes|required`) whenever the field genuinely must be sent.
More examples
min across all four value types
The error messages differ per type — "at least 8 characters", "at least 1", "at least 2 items" — because Laravel picks the message variant from the companion rule. That is another reason to always state `string`, `integer`, `array` or `file` explicitly: without it the message is wrong as well as the check.
<?php
use Illuminate\Support\Facades\Validator;
// String: at least 8 characters.
$a = Validator::make(['password' => 'secret'], ['password' => 'string|min:8']);
// Numeric: the value must be at least 1.
$b = Validator::make(['quantity' => 3], ['quantity' => 'integer|min:1']);
// Array: at least 2 elements.
$c = Validator::make(['tags' => ['php']], ['tags' => 'array|min:2']);
var_dump($a->passes()); // bool(false) - 6 characters
var_dump($b->passes()); // bool(true) - 3 >= 1
var_dump($c->passes()); // bool(false) - count 1
print_r($a->errors()->all());
// Array
// (
// [0] => The password field must be at least 8 characters.
// )Files are measured in kilobytes
`min:1` on a file means one kilobyte, not one byte — a useful guard against truncated or zero-length uploads. Confusing the unit is a common source of rules that appear to do nothing: `min:1024` on an avatar quietly demands a one-megabyte image.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreAvatarRequest extends FormRequest
{
public function rules(): array
{
return [
// Between 1 KB and 2048 KB (2 MB).
'avatar' => ['required', 'image', 'min:1', 'max:2048'],
];
}
}
// echo $request->file('avatar')->getSize(); // bytes
// echo $request->file('avatar')->getSize() / 1024; // what min/max comparemin versus min_digits
The two rules agree here but diverge on leading zeros and on magnitudes that share a digit count. When the requirement is really about formatting — a 4-digit PIN, a 10-digit phone number — `min_digits`/`max_digits` or `digits_between` express it, while `min` expresses a numeric floor.
<?php
use Illuminate\Support\Facades\Validator;
$pin = ['pin' => 42];
// min: is the number at least 1000?
var_dump(Validator::make($pin, ['pin' => 'integer|min:1000'])->passes());
// min_digits: does the number have at least 4 digits?
var_dump(Validator::make($pin, ['pin' => 'integer|min_digits:4'])->passes());
// Both reject 42, but they say different things:
$long = ['pin' => 9999];
var_dump(Validator::make($long, ['pin' => 'integer|min:1000'])->passes());
var_dump(Validator::make($long, ['pin' => 'integer|min_digits:4'])->passes());
// bool(false)
// bool(false)
// bool(true)
// bool(true)
Discussion