URL Slug Regex
A slug is the readable part of a URL path. This pattern keeps it to lower-case letters and digits, with single hyphens between words.
One case per line; the m flag makes ^ and the end anchor work line by line.
Link optionspattern only
The address bar holds the pattern, flags and replacement, so Copy link shares them. Your test text stays out of it unless you include it (up to 2,000 characters), because it may be private. Nothing is sent to a server.
Matches
6matches
The first is “hello-world”, at position 0.
- Groups
- none
- Characters matched
- 65 of 146
What the pattern meansHover or tap a part to see it in the pattern and what it matched
How this works: Method, 5 sources, Checked against 1 worked example,
How this works
Method
Your pattern runs in your own browser’s JavaScript engine, in a background worker that is stopped after 1.5 seconds, so a pattern that backtracks catastrophically can’t freeze the page. The explanation comes from our own parser of the ECMAScript pattern grammar, checked against the engine; what each part matched is found by wrapping that part in one more group and running the pattern again. Conversions to other flavours only rewrite the syntax and list what their documentation says works differently.
Sources
How it’s tested
One worked example for this page is checked by automated tests before every release: given the inputs, the tool must show the expected answer.
Changes
- First published, with a library of 19 common patterns and their test cases.
Worked example
Take hello-world, the first case in the tester. Reading the pattern left to right, each part takes its share of the text:
^The start of the text (matches a position, no characters)[a-z0-9]+One or more characters, each a–z or 0–9 matches hello(?:-[a-z0-9]+)*A group (not captured), zero or more times: matches -world$The end of the text (matches a position, no characters)
How the slug regex works
[a-z0-9]+ reads the first word: one or more lower-case letters or digits. (?:-[a-z0-9]+)* then allows any number of further words, each introduced by exactly one hyphen. Because a hyphen must always be followed by at least one letter or digit, the pattern can never end in a hyphen or contain two in a row.
The anchors make sure nothing else is in the string: no leading hyphen, no spaces and no punctuation. The structure, a word followed by zero or more hyphen-word pairs, is a common way to say "items separated by a delimiter" without allowing empty items.
Keeping slugs to this alphabet means they never need percent-encoding in a URL and read the same everywhere they are shown.
- Letters, digits, hyphen, period, underscore and tilde are the unreserved characters of a URI, so a slug made only of them never needs percent-encoding. Source: RFC 3986, section 2.3 (unreserved characters).
- Google recommends hyphens rather than underscores to separate words in URLs, and readable words rather than long ID numbers. Source: Google Search Central, URL structure best practices.
Test cases
Every case runs as an automated test of this page’s pattern, so the table can’t drift from what the pattern really does.
| Text | Result | Why |
|---|---|---|
| hello-world | Passes | two words |
| regex-tester | Passes | the slug of this tool |
| 2026-roadmap | Passes | digits are fine at the start |
| a | Passes | a single character |
| top-10-tips-for-beginners | Passes | many words |
| utf8 | Passes | letters and digits without a hyphen |
| Hello-World | Fails | upper case |
| hello--world | Fails | a double hyphen |
| -hello | Fails | a leading hyphen |
| hello- | Fails | a trailing hyphen |
| hello_world | Fails | an underscore |
| hello world | Fails | a space |
| café-au-lait | Fails | an accented letter |
What it doesn’t check
- The regex checks a slug; it does not make one. To turn a title into a slug, lower-case it, remove accents with normalize("NFD") and a replace of the combining marks, then replace each run of other characters with a single hyphen.
- Accented and non-Latin letters are rejected; if your site uses them in URLs, allow \p{Ll} with the u flag instead of a-z.
- It does not limit length, so add a maximum in code if slugs go into a database column or a file name.
The same pattern in other languages
Converted automatically from the JavaScript version; the tester above always runs JavaScript.
| Flavour | Pattern | Notes |
|---|---|---|
| Python | ^[a-z0-9]+(?:-[a-z0-9]+)*\Z | |
| PCRE | ^[a-z0-9]+(?:-[a-z0-9]+)*\z | |
| Go | ^[a-z0-9]+(?:-[a-z0-9]+)*$ | |
| Java | ^[a-z0-9]+(?:-[a-z0-9]+)*\z | |
| .NET | ^[a-z0-9]+(?:-[a-z0-9]+)*\z |
Sources
Frequently Asked Questions
Why use hyphens instead of underscores in slugs?
Search engines treat a hyphen as a word separator, and Google recommends it for URLs. Hyphens also stay visible when a link is underlined, where an underscore can disappear into the line.
How do I allow upper-case letters in a slug?
Add the i flag, or widen each class to include A to Z. Most sites lower-case slugs instead, because some servers treat paths as case-sensitive and two spellings would become two pages.
How do I turn a title into a slug that passes this check?
Lower-case the title, strip accents, replace every run of characters that are not letters or digits with one hyphen, and trim hyphens from both ends. The result always matches this pattern unless the title had no letters or digits at all.