regex
Validates a field against a regular expression using PHP's preg_match, delimiters included.
regex:patternParameters
| Parameter | Type | Description |
|---|---|---|
$pattern | string | A pattern in the form preg_match() expects, including its delimiters and any modifiers — for example /^.+@.+$/i. |
Errors
An invalid pattern makes preg_match() emit a PHP warning and the field fails; the rule itself does not throw, and validate() raises Illuminate\Validation\ValidationException on failure as usual.
regex matches the field against a pattern with PHP's preg_match(). The pattern must be written exactly as preg_match() wants it, delimiters and modifiers included: 'email' => 'regex:/^.+@.+$/i'. The mirror rule not_regex:pattern fails when the pattern does match.
When to reach for it
- Formats a built-in rule does not cover: internal SKUs, licence keys, slugs, invoice references.
- Character-class restrictions on a username or handle.
- As a last resort —
email,url,uuid,ip,alpha_dashandinare all better maintained than a hand-written pattern for the same job.
What trips people up
The documentation carries an explicit warning: when using regex or not_regex, specify the rules as an array rather than a pipe-delimited string. A rule string is split on |, so 'required|regex:/^(a|b)$/' is torn into fragments and the pattern is destroyed. The array form ['required', 'regex:/^(a|b)$/'] is safe.
Two further points. Commas inside a pattern are fine — the parser does not split regex parameters on commas the way it does for other rules. And a non-matching value produces the generic message "The field format is invalid", which tells the user nothing; supply your own message explaining the expected shape.
Example
<?php
use Illuminate\Support\Facades\Validator;
$validator = Validator::make([
'sku' => 'ab-123',
'plan' => 'gold',
], [
// Array syntax: the pipe inside the pattern stays intact.
'sku' => ['required', 'regex:/^[A-Z]{2}-\d{4}$/'],
'plan' => ['required', 'regex:/^(free|pro|team)$/'],
]);
print_r($validator->errors()->toArray());
// Array
// (
// [sku] => Array
// (
// [0] => The sku field format is invalid.
// )
// [plan] => Array
// (
// [0] => The plan field format is invalid.
// )
// )When to use it
- Enforce an internal SKU shape such as two letters, a hyphen and four digits.
- Restrict a username to lowercase letters, digits and underscores.
- Reject reserved words in a slug field with not_regex.
- Validate a national phone or postcode format that has no built-in rule.
Frequently asked questions
Why does my regex validation rule break when the pattern contains a pipe?
Because a pipe-delimited rule string is split on every |, which tears the pattern apart. Write the rules as an array instead — ['required', 'regex:/^(free|pro)$/'] — exactly as the Laravel documentation warns.
Do I need delimiters in a Laravel regex rule?
Yes. The rule passes the pattern straight to preg_match(), so it must include valid delimiters and any modifiers, as in regex:/^.+@.+$/i. A bare pattern without delimiters triggers a preg_match warning and fails the field.
How do I change the "format is invalid" message for a regex rule?
Add an entry keyed field.regex in a form request's messages() method, or pass it as the third argument to Validator::make(). The default message never describes the expected shape, so a custom one is worth writing.
More examples
Why the pipe syntax breaks
This is the failure the documentation warns about. Splitting on the pipe leaves the validator holding rule names that were meant to be regex alternatives, so you get a BadMethodCallException about a missing rule rather than a clean validation error. The array form is the fix, and it is worth using for every rule set so the question never comes up.
<?php
use Illuminate\Support\Facades\Validator;
$input = ['plan' => 'pro'];
// Broken: the rule string is split on every |, so the pattern becomes
// the three fragments 'regex:/^(free', 'pro' and 'team)$/'.
$broken = Validator::make($input, [
'plan' => 'required|regex:/^(free|pro|team)$/',
]);
// Correct: nothing is split, the pattern reaches preg_match() whole.
$correct = Validator::make($input, [
'plan' => ['required', 'regex:/^(free|pro|team)$/'],
]);
var_dump($correct->passes());
// bool(true)
// The $broken validator does not merely fail — it tries to resolve
// rules named "pro" and "team", which do not exist.not_regex and a useful message
Two patterns on one field, each with its own message keyed as field.rule — without them both failures read "The slug field format is invalid". The reference rule also shows that a comma inside a pattern is safe: regex parameters are not split on commas the way other rules' parameters are.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePageRequest extends FormRequest
{
public function rules(): array
{
return [
'slug' => [
'required',
'string',
'regex:/^[a-z0-9]+(?:-[a-z0-9]+)*$/',
'not_regex:/^(admin|api|login)$/i',
],
'reference' => ['nullable', 'regex:/^INV-\d{4},\d{2}$/'],
];
}
public function messages(): array
{
return [
'slug.regex' => 'The slug may only contain lowercase letters, numbers and single hyphens.',
'slug.not_regex' => 'That slug is reserved.',
];
}
}
Discussion