Quick Answer
A good URL slug is short, descriptive, lowercase, and stable. Use hyphens between words, keep only the terms that help identify the page, and normalize accented text before slug generation.
What a Slug Should Do
A slug should make the URL readable to humans while staying easy to manage in your CMS or application. It should communicate the page topic clearly without turning into a full sentence or a dump of every keyword variation.
Rules for SEO-Friendly Slugs
- Use lowercase consistently
- Use hyphens, not underscores, for public page URLs
- Keep the slug descriptive but compact
- Remove punctuation and unstable decorative text
- Normalize accented characters before transliteration
- Do not keep dates or update markers unless they matter long term
- Aim for 3-5 words that capture the page topic
Hyphen vs Underscore
| Choice | Recommendation | Why |
|---|---|---|
| Hyphen | Use by default | Most readable and standard for public URLs |
| Underscore | Avoid for public content pages | Less readable and less standard for SEO-facing slugs |
Maximum Slug Length
There is no strict character limit, but practical guidelines exist. Keep slugs under 60-70 characters. Longer slugs get truncated in search results and are harder to share. More importantly, every word in the slug should earn its place. If removing a word does not change the meaning, remove it.
| Length | Assessment | Example |
|---|---|---|
| 3-5 words | Ideal | /guides/seo-friendly-slugs |
| 6-8 words | Acceptable if needed for clarity | /guides/how-to-create-seo-friendly-url-slugs |
| 9+ words | Too long, trim stop words and redundancy | /guides/the-complete-guide-to-creating-seo-friendly-url-slugs-for-your-website |
When to Remove Stop Words
Remove stop words when they add no meaning, but keep them if dropping them makes the slug awkward or ambiguous. The goal is not maximum compression. The goal is a readable and stable identifier.
Internationalization and Transliteration
Slugs must work in URLs, which means they should contain only ASCII letters, digits, and hyphens. Non-ASCII text requires transliteration: converting characters from other scripts into ASCII equivalents.
Accented Latin Characters
Normalize to NFD (decomposed form) first, then strip the combining diacritical marks. This converts characters like cafe to cafe reliably.
CJK Characters (Chinese, Japanese, Korean)
CJK characters do not transliterate to ASCII in a meaningful way without a romanization library. Options include:
- Use pinyin for Chinese (e.g., a library like
pinyinin Python orpinyin-proin JavaScript) - Use romaji for Japanese (Hepburn romanization)
- Use revised romanization for Korean
- Alternatively, use a numeric ID or hash as the slug and rely on the page title for readability
Arabic and Cyrillic
Both scripts have established transliteration tables. Use a library like transliterate (JavaScript) or text-unidecode (Python) that maps each character to its closest ASCII equivalent. Always test the output: automated transliteration can produce awkward or misleading results for some words.
Accents, Unicode, and Imported Titles
If your titles contain accented characters or come from mixed systems, normalize the text before slug generation. This reduces inconsistent output and makes transliteration more stable. See the Unicode normalization guide if you are dealing with NFC vs NFD problems.
CMS-Specific Advice
WordPress
WordPress auto-generates slugs from post titles but does not handle CJK text well by default. Install a transliteration plugin for non-Latin scripts. To edit a slug, use the "Permalink" field in the post editor. Avoid changing slugs after publication unless you set up redirects.
Next.js and File-Based Routing
In Next.js, the slug is the filename or folder name in the app/ or pages/ directory. Use kebab-case for folder and file names. For dynamic slugs from a database, sanitize at the data layer before passing to generateStaticParams() or getStaticPaths().
Custom CMS Systems
Build slug generation into your content creation API. Validate that every slug is unique within its URL path, enforce lowercase and hyphen-only rules at the database level, and store the slug as a separate indexed column rather than deriving it at render time.
Redirect Strategy When Slugs Change
Changing a published slug breaks existing links, bookmarks, and search engine rankings. If you must change a slug, always set up a 301 (permanent) redirect from the old URL to the new one.
- 301 redirect: Tells search engines the page has permanently moved. Link equity transfers to the new URL over time.
- Never use 302: A 302 (temporary) redirect tells search engines the old URL might come back, so they may not transfer ranking signals.
- Keep a redirect map: Maintain a table of old-slug to new-slug mappings. In a CMS, store the history of previous slugs for each page and auto-redirect any old slug to the current one.
- Batch changes: If you are changing slug conventions across many pages, do it in one deployment with all redirects in place simultaneously.
Slug Stability and Versioning
A stable slug is one that does not need to change when the content is updated. Design slugs for longevity:
- Do not include the year unless the content is genuinely time-specific (e.g., annual reports).
- Do not include version numbers in the slug. Use
/api-authenticationnot/api-authentication-v2. - Avoid including the author name, category hierarchy, or other metadata that might change.
- If you need versioned content, use a separate URL parameter or path segment (
/docs/v2/authentication) rather than embedding versions in the slug itself.
Programmatic Slug Generation
JavaScript
function slugify(text) {
return text
.normalize("NFD") // decompose accents
.replace(/[\u0300-\u036f]/g, "") // strip diacritical marks
.toLowerCase()
.trim()
.replace(/[^a-z0-9\s-]/g, "") // remove non-alphanumeric chars
.replace(/[\s_]+/g, "-") // spaces and underscores to hyphens
.replace(/-+/g, "-") // collapse multiple hyphens
.replace(/^-|-$/g, ""); // trim leading/trailing hyphens
}
// slugify("Cafe Expose: A Developer's Guide!")
// => "cafe-expose-a-developers-guide"
Python
import re
import unicodedata
def slugify(text):
text = unicodedata.normalize("NFD", text)
text = text.encode("ascii", "ignore").decode("ascii")
text = text.lower().strip()
text = re.sub(r"[^a-z0-9\s-]", "", text)
text = re.sub(r"[\s_]+", "-", text)
text = re.sub(r"-+", "-", text)
return text.strip("-")
# slugify("Cafe Expose: A Developer's Guide!")
# => "cafe-expose-a-developers-guide"
Common Slug Mistakes
- Keeping punctuation and update markers such as
(updated)without need - Using percent-encoded titles instead of real slugs
- Changing slugs too often after publishing
- Removing too many words and losing meaning
- Skipping cleanup when titles contain hidden Unicode characters
- Including query parameters or fragments in what should be a path-only slug
FAQ
Should a slug match the title exactly?
No. It should match the topic clearly, but it can be shorter and cleaner than the full title. Remove stop words, punctuation, and decorative text that does not help identify the page.
Should I include the year in a slug?
Only if the year is genuinely part of the page identity (e.g., annual reports or event pages). Otherwise it makes future updates harder and forces a slug change when the content is refreshed.
Can hidden characters affect a slug?
Yes. Hidden or inconsistent Unicode characters (zero-width spaces, right-to-left marks, soft hyphens) can create messy or unstable slug output if you do not normalize first.
How do I handle CJK characters in slugs?
Use a romanization library specific to the language: pinyin for Chinese, romaji for Japanese, revised romanization for Korean. If the romanized output is too long or awkward, use a numeric or hash-based slug instead and rely on the page title for human readability.
What happens to SEO if I change an existing slug?
Changing a slug without a 301 redirect breaks all existing links and causes the page to lose its accumulated search ranking. Always set up a permanent redirect from the old URL to the new one before deploying the change.
Should I use trailing slashes in slugs?
Pick one convention (trailing slash or no trailing slash) and enforce it site-wide. Inconsistency creates duplicate content issues. If your framework adds trailing slashes by default, redirect the non-trailing-slash version to the canonical form.
Is it better to use IDs or words in slugs?
Use words for content pages where readability and SEO matter. Use IDs or hashes for app routes, user-generated content, or pages where the title may change frequently. A hybrid approach like /products/42-wireless-keyboard combines uniqueness with readability.
Related Tools
- URL Slug Generator to generate clean slugs quickly
- URL Encoder / Decoder for URL escaping, which is a different job than slug creation
Related Guides
- Unicode Normalization for accent and normalization edge cases
- Hidden Unicode Characters for invisible-character cleanup