# Unfriendly URL slug

> URLs with IDs, underscores, or capital letters are hard to read, share, and rank. Use clean, lowercase, hyphenated keyword slugs.

_Category: Search visibility · Detector `seo` · Check `slug-unfriendly` · Severity: info_

A URL like /Blog_Post_00f3a2b1 is hard to read, hard to share, and gives search engines no keyword signal. Clean, human-readable slugs get more clicks when the URL shows in results and are easier to link to. AI-built apps frequently route by database ID or UUID and keep underscores or camelCase from variable names.

## Symptoms

- URLs contain UUIDs or numeric IDs
- Slugs use underscores or capital letters instead of hyphens
- The address bar shows an unshareable, meaningless path

## How VibeCheck detects it

The `seo` detector flags this live in the browser and reports it to the widget's Problems list — and to your coding agent over MCP.

- **Issue string:** `Unfriendly URL slug`
- **Threshold:** path contains a UUID, underscore, or capital letters

## Root causes

- Routes are keyed by database ID or UUID
- Slugs were derived from variable names (underscores, camelCase)
- No slugify step converts titles into clean paths

## The fix

Use lowercase, hyphen-separated slugs made of real words — /blog/scaling-postgres, not /Blog_Post_00f3a2b1. Generate slugs from titles with a slugify step, and if you must keep an ID, pair it with a readable slug and 301-redirect the bare-ID form.

### Steps

1. Add a slugify step that lowercases and hyphenates titles
2. Route by the clean slug (optionally slug + id)
3. 301-redirect old ID/underscore URLs to the new slug

```js
const slugify = (s) =>
  s.toLowerCase().trim()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')

slugify('Scaling Postgres to 1M rows') // → "scaling-postgres-to-1m-rows"
```

## Framework-specific fixes

### Next.js

Folder and dynamic-segment names become the URL. Name the `[slug]` segment from a clean slug field, not an id.

_Route by slug, not id_

```bash
app/blog/[slug]/page.tsx      # /blog/scaling-postgres  ✅
app/blog/[id]/page.tsx        # /blog/00f3a2b1          ❌
```

### Vanilla JS

Generate clean slugs when creating content and map them to your routes; redirect legacy ID URLs.

```js
// store a slug alongside the id, route on the slug
router.get('/blog/:slug', handler)
```

## FAQ

### Hyphens or underscores in URLs?

Hyphens. Google treats hyphens as word separators but underscores as joiners, so “scaling_postgres” reads as one token while “scaling-postgres” reads as two words.

### Can I keep the database ID in the URL?

You can pair it with a readable slug (/blog/scaling-postgres-42), but a bare ID or UUID is unfriendly. If you change the scheme, 301-redirect the old URLs.

## Related problems

- [Missing canonical link](https://vibecheck.wcgw.fun/fix/missing-canonical-url.md) — Search visibility
- [Missing og:url](https://vibecheck.wcgw.fun/fix/missing-og-url.md) — Search visibility
- [Missing page title](https://vibecheck.wcgw.fun/fix/missing-page-title.md) — Search visibility
- [Missing or invalid sitemap.xml](https://vibecheck.wcgw.fun/fix/missing-sitemap.md) — Search visibility

---

Fix guide from VibeCheck — https://vibecheck.wcgw.fun/fix/unfriendly-url-slug. Full site index for LLMs: https://vibecheck.wcgw.fun/llms.txt
