Turn a title into a clean URL slug. The tool
transliterates accents, drops punctuation and collapses spaces
into hyphens, so "Đà Nẵng: A Developer's Guide" becomes
da-nang-a-developers-guide. Paste a list of post
titles and you get one slug per line back.
10 Things I Learned Building a Café Menu API
Đà Nẵng: A Developer's Guide
Why "Move Fast" Broke Our Deploy Pipeline 10-things-i-learned-building-a-cafe-menu-api
da-nang-a-developers-guide
why-move-fast-broke-our-deploy-pipeline Café becomes cafe, Đà Nẵng becomes da-nang. A percent-encoded accent also works in a browser, but a pasted link then shows caf%C3%A9 instead of a readable word.
Quotes, colons, apostrophes and emoji are removed. An apostrophe is deleted instead of replaced, so developer's becomes developers instead of developer-s.
Runs of spaces and symbols become a single hyphen, and leading or trailing hyphens are trimmed.
Lowercase is on by default. Most servers treat /About and /about as different paths, so a mixed-case slug invites broken links and duplicate pages.
Changing a slug later means either a redirect or a broken link,
so choose it before you publish. Keep slugs short.
The first four or five meaningful words carry the topic, and the
rest adds length without adding meaning. Skip the date unless the
content is tied to it. For example, /2024-guide-to-css
looks stale a year later, while /guide-to-css can be
updated in place.
Use hyphens, not underscores. Google has treated
hyphens as word separators and underscores as joiners for well
over a decade, so web_dev_utility reads as one token
and web-dev-utility reads as three words.
function slugify(input, sep = "-") {
return input
.normalize("NFD") // split accents from letters
.replace(/[\u0300-\u036f]/g, "") // drop the accents
.replace(/['\u2018\u2019]/g, "") // apostrophes join, not separate
.replace(/[^a-zA-Z0-9]+/g, " ")
.trim()
.split(/\s+/)
.join(sep)
.toLowerCase();
}
console.log(slugify("10 Things I Learned Building a Café API"));
// 10-things-i-learned-building-a-cafe-api
// NFD does not handle every letter: ø, đ and ł have no combining form,
// so map those explicitly if your content needs them. <?php
function slugify(string $text, string $sep = '-'): string {
// Transliterate to ASCII (needs the intl extension)
$text = transliterator_transliterate('Any-Latin; Latin-ASCII', $text);
$text = preg_replace("/['\x{2018}\x{2019}]/u", '', $text);
$text = preg_replace('/[^A-Za-z0-9]+/', $sep, $text);
$text = trim($text, $sep);
return strtolower($text);
}
echo slugify("10 Things I Learned Building a Café API"), PHP_EOL;
// Laravel: Str::slug($title) does the same thing, with a language argument
// for locale-specific rules such as German ä -> ae. import re
import unicodedata
def slugify(text: str, sep: str = "-") -> str:
text = unicodedata.normalize("NFKD", text)
text = text.encode("ascii", "ignore").decode("ascii")
text = re.sub(r"['\u2018\u2019]", "", text)
text = re.sub(r"[^A-Za-z0-9]+", " ", text).strip()
return sep.join(text.split()).lower()
print(slugify("10 Things I Learned Building a Café API"))
# Django has django.utils.text.slugify, which does the same
# with allow_unicode as an option. Percent-encoded Unicode in a URL does work: /caf%C3%A9 loads and Google indexes it. The trouble comes from the tools around it. The link shows as %C3%A9 when pasted into a chat, some analytics tools decode it twice, and older systems corrupt it. Transliterating to ASCII loses the accent but gives you a URL that stays readable wherever it is copied.
This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.
It transliterates them: café becomes cafe, Ünal becomes unal, Łódź becomes lodz. A percent-encoded accent also works in modern browsers, but a link pasted into a chat then shows caf%C3%A9 instead of a readable word.
Yes. Type _ or any other string into the Separator field. However, we recommend hyphens for a public URL, because Google has said for years that it reads hyphens as word breaks and underscores as part of the word.
Only when you tick Drop stop words. It removes short words such as the, of, and, to and with from titles longer than two words. That shortens a long slug but can make it read oddly, so it is off by default.
Russian Cyrillic is transliterated letter by letter, so Привет becomes privet. Greek, Chinese, Japanese, Korean, Arabic, Hebrew and letters outside the Russian alphabet are dropped, because the tool has no mapping for them. Write those slugs by hand.
Yes. Each input line produces one slug on the matching output line, so you can paste a list of post titles and copy the slugs back in the same order.
For identifiers instead of URLs, the case converter covers camelCase and snake_case. If a URL already exists and you need to read it, the URL parser breaks it into parts and the URL decoder unwraps percent-encoding.