Developer Toolbox

Regex: URL slug

A slug is the readable part of a URL, like regex-cheatsheet. The pattern allows lower-case letters and digits in runs joined by single dashes, so a slug cannot start or end with a dash or contain two in a row.

Open in Regex Tester The pattern and every example below are filled in.

Pattern

^[a-z0-9]+(?:-[a-z0-9]+)*$

How it works

^
Start of the string.
[a-z0-9]+
A run of lower-case letters and digits.
(?:-[a-z0-9]+)*
Any number of further runs, each after a single dash.
$
End of the string.

Matches

  • hello-world
  • post-2026
  • a

Doesn't match

  • Hello-World
  • -start
  • double--dash
  • end-
  • with_underscore

In your language

JavaScript
/^[a-z0-9]+(?:-[a-z0-9]+)*$/

A literal; new RegExp(source, flags) builds the same from a string.

Python
re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")

A raw string, so backslashes reach re as written. re.ASCII keeps \d to 0-9, as in JavaScript (Python matches any Unicode digit otherwise). Use re.fullmatch to test a whole string.

Java
Pattern.compile("^[a-z0-9]+(?:-[a-z0-9]+)*$")

A normal string literal, so every backslash is doubled. matcher(s).matches() tests the whole string.

Go
regexp.MustCompile(`^[a-z0-9]+(?:-[a-z0-9]+)*$`)

A raw string in backticks. RE2 runs in linear time but has no lookaround and no backreferences.

PHP
preg_match('/^[a-z0-9]+(?:-[a-z0-9]+)*$/D', $input)

PCRE with / delimiters inside a single-quoted string. Without the D modifier, $ also matches before a final newline, so it is added to patterns that end in $.

C#
new Regex(@"^[a-z0-9]+(?:-[a-z0-9]+)*$")

A verbatim string: backslashes stay, a quote is doubled. RegexOptions.ECMAScript keeps \d to 0-9, as in JavaScript. $ also matches before a final newline; to reject one, end the pattern with \z instead.

Common mistakes

  • Generate, then validate

    Build slugs from titles in code: lower-case, strip accents (normalize to NFD and drop the combining marks), replace every run of other characters with one dash, trim dashes from the ends. The pattern then only guards slugs typed by hand.

  • Titles outside Latin script

    A Japanese or Russian title leaves nothing after stripping. Transliterate it, or put an id in the URL instead.

  • Dashes, not underscores

    Google recommends hyphens rather than underscores between words in URLs, and paths are case-sensitive, so My-Page and my-page are two addresses. Keep slugs lower-case with dashes.