numeric
Validates that a field is numeric, accepting integers, floats and numeric strings from request input.
numeric | numeric:strictParameters
| Parameter | Type | Description |
|---|---|---|
$strictoptional | string | Literal flag. When present, only an actual int or float value passes; numeric strings such as "19.99" are rejected. |
Errors
Nothing on its own — a failing rule adds a message to the validator's MessageBag, and Illuminate\Validation\ValidationException is thrown only when you call validate() or validateWithBag() on a failing validator.
Changelog
- PHP 12.xAdded the strict parameter (numeric:strict), which rejects numeric strings and passes only real int or float values.
numeric is the rule for anything you will later do arithmetic with: prices, quantities, latitudes, scores. It mirrors PHP's is_numeric(), so integers, floats, and the numeric strings that HTTP requests actually deliver all pass, including "-3", "19.99" and exponent forms like "1e4".
When to reach for it
- Any field arriving from a form or JSON body where the value is a measurement or amount.
- As the companion to
integerwhen you want to be sure the input is a number as well as an integer-shaped string. - With
decimal:2when the number of decimal places matters, orbetween/min/maxfor range checks.
What trips people up
The presence of numeric changes what min, max, size and between mean. In ['numeric', 'min:5'] the value must be at least 5; drop numeric and min:5 suddenly means the string must be five characters long. This silent switch is the single most common source of "my validation passes the wrong thing" reports.
The rule also never converts anything. After validation the value is still the string "19.99" unless you cast it yourself or read it through $request->float('amount'). If you genuinely require a JSON number rather than a quoted one, use numeric:strict.
Example
<?php
use Illuminate\Support\Facades\Validator;
$validator = Validator::make([
'amount' => '19.99',
'discount' => 'free',
], [
'amount' => ['required', 'numeric', 'min:0.01'],
'discount' => ['nullable', 'numeric'],
]);
print_r($validator->errors()->toArray());
// Array
// (
// [discount] => Array
// (
// [0] => The discount field must be a number.
// )
// )When to use it
- Validate a submitted price or invoice amount before casting it to a decimal column.
- Accept a latitude/longitude pair posted as JSON strings from a mobile client.
- Bound a paginated API's per_page parameter with numeric plus min and max.
Frequently asked questions
What is the difference between numeric and integer in Laravel validation?
numeric accepts anything is_numeric() accepts, including floats and numeric strings, while integer only accepts values PHP's FILTER_VALIDATE_INT filter accepts. Use both together when you want a whole number that is also definitely a number: ['required', 'numeric', 'integer'].
Why does numeric accept a string like "19.99"?
Because HTTP request bodies are strings — every form field arrives as a string, so a rule that rejected them would fail on ordinary form input. If your client sends real JSON numbers and you want to enforce that, use numeric:strict, added in Laravel 12.
Does the numeric rule cast the value to a number?
No. validated() and $request->input() still return the original string. Cast it yourself with (float), use $request->float('amount'), or let an Eloquent cast on the model do it.
More examples
min and max flip meaning
The same input and the same min:5 give opposite results. With numeric present, min:5 compares the value (7 >= 5, passes). Without it, min:5 compares the string length (one character, fails). Always state numeric, integer, array or file explicitly so the size rules read the way you intend.
<?php
use Illuminate\Support\Facades\Validator;
$input = ['code' => '7'];
$asNumber = Validator::make($input, [
'code' => ['numeric', 'min:5'],
]);
$asString = Validator::make($input, [
'code' => ['string', 'min:5'],
]);
var_dump($asNumber->passes(), $asString->passes());
// bool(true)
// bool(false)Strict numeric for a JSON API
Only the field that arrived as a real JSON number survives numeric:strict; the quoted "12.5" fails. This is useful on machine-to-machine endpoints where you control the client, but never on an HTML form — a browser posts every field as a string, so strict would reject all of them.
<?php
use Illuminate\Support\Facades\Validator;
$payload = json_decode('{"quoted": "12.5", "real": 12.5}', true);
$validator = Validator::make($payload, [
'quoted' => ['numeric:strict'],
'real' => ['numeric:strict'],
]);
print_r($validator->errors()->keys());
// Array
// (
// [0] => quoted
// )Price with a fixed scale
A realistic form request. numeric admits the string "4.50" that the browser posts, decimal:2 pins the scale so "4.5" is rejected before it reaches a money column, and priceInCents shows the cast you still have to perform yourself — validation never mutates the input.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductRequest extends FormRequest
{
public function rules(): array
{
return [
'price' => ['required', 'numeric', 'decimal:2', 'min:0'],
'weight_g' => ['required', 'numeric', 'between:1, 50000'],
];
}
public function priceInCents(): int
{
return (int) round($this->float('price') * 100);
}
}
Discussion