★ Web · regex
Regex for URL Slug
The standard SEO-friendly slug: lowercase letters and digits in words separated by single hyphens, with no leading, trailing or doubled hyphens.
- Runs in your browser
- No signup
Try the url slug pattern
Read it in plain English (best-effort)
- ^start of a line
- [a-z0-9]one character from: a–z, 0–9
- +one or more of the previous
- (?:start a group (not captured)
- -the character '-'
- [a-z0-9]one character from: a–z, 0–9
- +one or more of the previous
- )end of group
- *zero or more of the previous
- $end of a line
One sample per line works well with the m flag on anchored patterns.
The pattern, piece by piece
/^[a-z0-9]+(?:-[a-z0-9]+)*$/| Part | What it does |
|---|---|
^[a-z0-9]+ | first word: lowercase letters or digits |
(?:-[a-z0-9]+)* | more words, each after exactly one hyphen |
$ | end of the string |
What it accepts and rejects
Every sample below is checked automatically in JavaScript and Python. The tester above is preloaded with all of them, one per line.
| Should match | |
|---|---|
hello-world | ✓ |
a | ✓ |
post-123 | ✓ |
2026-recap | ✓ |
seo | ✓ |
my-first-post-2 | ✓ |
| Should not match | |
|---|---|
Hello-World | ✗ |
hello--world | ✗ |
-hello | ✗ |
hello- | ✗ |
hello_world | ✗ |
hello world | ✗ |
Copy it into your code
RE2-safeNo lookarounds or backreferences, so the same pattern works in Go's RE2 engine and in Rust's regex crate.
const slugRe = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
export function isValidSlug(value) {
return slugRe.test(value.trim());
}When not to use regex for this
Don't make users type valid slugs. Generate them: lowercase the title, strip accents, replace non-alphanumerics with hyphens and collapse repeats. Use the regex to validate the result.
Questions engineers actually ask
Should slugs allow uppercase?
Are underscores bad for SEO?
What is catastrophic backtracking?
More web patterns
- Email AddressPragmatic email check: catches typos without rejecting real addresses.^[A-Za-z0-9_%+-]+(?:\.[A-Za-z0-9_%+-]+)*@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*\.[A-Za-z]{2,}$
- URLhttp(s) URLs with a real domain, optional port, path, query and fragment.^https?:\/\/(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}(?::\d{1,5})?(?:[\/?#]\S*)?$
- Domain NameHostnames like example.com or sub.example.co.uk, including punycode.^(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}$
- IPv4 AddressDotted-quad IPv4 with each octet 0–255 and no leading zeros.^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$
- IPv6 AddressFull and compressed (::) IPv6 addresses.^(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,7}:|(?:[0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,5}(?::[0-9A-Fa-f]{1,4}){1,2}|(?:[0-9A-Fa-f]{1,4}:){1,4}(?::[0-9A-Fa-f]{1,4}){1,3}|(?:[0-9A-Fa-f]{1,4}:){1,3}(?::[0-9A-Fa-f]{1,4}){1,4}|(?:[0-9A-Fa-f]{1,4}:){1,2}(?::[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:(?::[0-9A-Fa-f]{1,4}){1,6}|:(?:(?::[0-9A-Fa-f]{1,4}){1,7}|:))$
- Hex ColorCSS hex colours: #rgb, #rgba, #rrggbb and #rrggbbaa.^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$
- HTML TagFinds opening, closing and self-closing tags in a string. Not a parser.<\/?([A-Za-z][A-Za-z0-9-]*)\b[^<>]*>
Or browse the full regex library.
More from the workbench
Fine print
Tools: on the house.
Engineer: by the hour.
The regex was free. Code that doesn't need one is the upgrade: typed schemas, validated once at the edge, trusted everywhere after.
I'm Himanshu, an AI and full-stack engineer. I build MVPs, AI agents and the growth plumbing around them for early-stage startups.
