How to generate clean, SEO-friendly URL slugs — handling unicode, stop words, special characters, and maximum length.
A URL slug is the human-readable, SEO-friendly part of a URL that identifies a page:
https://blog.example.com/posts/how-to-format-json-like-a-pro
↑
This is the slug
Good slugs are short, descriptive, lowercase, and use hyphens as separators. They're a direct ranking signal in SEO and significantly affect click-through rates from search results.
The algorithm for converting a title to a slug:
function generateSlug(title) {
return title
.normalize('NFD') // Decompose unicode characters
.replace(/[\u0300-\u036f]/g, '') // Remove diacritics (é → e)
.toLowerCase() // Lowercase everything
.replace(/[^a-z0-9\s-]/g, '') // Remove non-alphanumeric
.trim() // Remove edge whitespace
.replace(/[\s]+/g, '-') // Replace spaces with hyphens
.replace(/[-]+/g, '-') // Collapse multiple hyphens
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
}
generateSlug('Hello, World! How are you?');
// → 'hello-world-how-are-you'
generateSlug('Héllo Wörld — Ünïcode');
// → 'hello-world-unicode'
The normalize('NFD') step is critical for international content:
// NFD decomposes accented characters into base + combining marks
'café'.normalize('NFD') // 'cafe\u0301' (e + combining accent)
// Then remove combining marks → 'cafe'
// Vietnamese example
'Nguyễn Thị Hương'.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
// → 'Nguyen Thi Huong'
Stop words are common words that add little value to SEO: a, an, the, and, or, in, on, at, to, for...
For blog posts and articles: Removing stop words creates shorter, more focused slugs:
Title: "A Beginner's Guide to Regular Expressions"
With stops: a-beginners-guide-to-regular-expressions
Without stops: beginners-guide-regular-expressions
For product names, proper nouns, or short titles: Keep stop words. Removing them from "The Dark Knight" produces "dark-knight" which loses SEO context.
Recommendation: Remove stop words only for long editorial titles (6+ words). Preserve them for names and brands.
There's no hard limit in HTTP, but practical limits apply:
When truncating, always cut at a word boundary:
function truncateSlug(slug, maxLength = 60) {
if (slug.length <= maxLength) return slug;
const truncated = slug.slice(0, maxLength);
return truncated.slice(0, truncated.lastIndexOf('-'));
}
truncateSlug('how-to-write-clean-maintainable-javascript-code-that-scales', 50);
// → 'how-to-write-clean-maintainable-javascript-code'
When two posts have the same title, you need a disambiguation strategy:
// Option 1: Append a counter
async function uniqueSlug(base) {
let slug = base;
let counter = 1;
while (await slugExists(slug)) {
slug = `${base}-${counter++}`;
}
return slug;
}
// 'javascript-tips', 'javascript-tips-2', 'javascript-tips-3'
// Option 2: Append a short ID (better for high-volume systems)
import { nanoid } from 'nanoid';
const slug = `${base}-${nanoid(6)}`;
// 'javascript-tips-a3f9kz'
1. Include the primary keyword early in the slug:
Good: /typescript-discriminated-unions
Bad: /a-guide-to-using-discriminated-unions-in-typescript
2. Don't change slugs once indexed. If you must change a slug, set up a 301 permanent redirect from the old URL to the new one.
3. Avoid dates in slugs (unless the date is the point, like /2025/01/15/...). Dates make content feel stale and require a redirect when you update the article.
4. Use hyphens, not underscores. Google treats hyphens as word separators but underscores as connectors. my-post = two words; my_post = one word.
5. Keep slugs consistent in depth:
/blog/post-title ← Good (flat structure)
/blog/category/post ← Also fine (nested, but consistent)
/b/c/d/post-title ← Bad (too deep, dilutes link equity)
Use HeoLab's Slug Generator to instantly convert titles to slugs with options for separator type, stop word removal, lowercase, and character limits. It also generates kebab-case, snake_case, dot.case, and camelCase variants at once.
The perfect slug is short, lowercase, hyphen-separated, keyword-rich, and free of special characters. Get the algorithm right once (or use a trusted library like slugify) and your URLs will serve both users and search engines well for years.
Slug Generator
Convert titles and text to URL-safe slugs. Handles unicode, special characters, and custom separators.
URL Encoder / Decoder
Encode and decode URL components and full URLs. Handle special characters for safe HTTP transmission.
URL Parser & Builder
Parse any URL into its components and rebuild it. Edit parts individually.