Why this comparison matters
If you migrate between CMSes, your URLs survive only if both systems agree on how to turn a title into a slug. They almost never do.
WordPress strips one character, Contentful strips another, Ghost lowercases differently, Strapi truncates at a different length. The same post titled “Cómo crear una API REST” lands at como-crear-una-api-rest in one system and c-mo-crear-una-api-rest in another. The redirects you set up after migration cover the obvious cases. The slug differences are the silent ones that bleed traffic.
This is the field reference, ordered by what each system actually does in 2026.
WordPress
WordPress strips accents using a built in function called remove_accents, which maps é to e, ñ to n, and so on. Spaces become hyphens. Lowercase. Stop words like “the” and “a” are kept by default but can be stripped with a plugin.
The gotcha: & becomes the literal word “and” in some locales but is stripped silently in others. If your title has an ampersand, the slug is unpredictable across language packs. To preview what WordPress would produce before you publish, the WordPress slug generator replicates the same remove_accents routine in your browser.
Ghost
Ghost is the most aggressive at cleaning. It strips accents, lowercases, replaces spaces with hyphens, removes most punctuation, and truncates at 50 characters by default. The result is consistently short and clean.
The gotcha: Ghost slugs include numeric suffixes for duplicates (my-post, my-post-2, my-post-3). If you publish a draft and then a full version with the same title, you end up with two URLs and one of them is dead weight. The Ghost slug generator on AldeaCode mirrors the same 50 character truncation so you can preview the URL before importing.
Contentful
Contentful does not generate slugs. Slugs are a field type you define on the model, and you fill them in manually or through a custom function in code. There is a slug generator UI but it is opt in.
The gotcha: nothing prevents your team from typing a slug with spaces or accents. If you use Contentful, set up a validation rule on the slug field. The default is “anything goes” and that is rarely what you want.
Strapi
Strapi has a uid field type that generates slugs from a target field. The slug is lowercased, accents stripped, spaces become hyphens. The character limit is 100 by default but you can change it.
The gotcha: the slug regenerates every time the source field changes, unless you mark it as locked. Edit a published post’s title and the URL silently changes.
Webflow
Webflow generates slugs automatically from the page title. Strips accents, lowercases, hyphenates. The character limit is 256 (the same as the URL pathname limit in most browsers).
The gotcha: Webflow does not enforce uniqueness across collections, only within. Two collections with the same slug can collide if you reorganise the site map.
Notion
Notion as a CMS (via tools like Super or Potion) uses the page title verbatim, encoded as a URL component. Spaces become %20, accents stay as percent encoded UTF-8.
The gotcha: this is the worst pattern for SEO. Search engines index the URL but readers see ugly encoded strings. If you use Notion as a CMS, run the title through a separate slug field that you maintain manually.
Astro and Next.js (file based)
In file based frameworks, the slug is the file name. my-post.md becomes /blog/my-post. There is no automatic generation, you choose the file name when you create the post.
The gotcha: you have to remember to follow your own naming convention. Plain text editors do not enforce hyphens, lowercase, or accent stripping. The slug generator on AldeaCode is useful here, paste the title, copy the slug, name the file accordingly.
Sanity
Sanity has a slug field type with a custom function. The default source.current derives the slug from the title field with sensible normalisation. You can override it with any function that returns a string.
The gotcha: the slug field accepts any string until you add a custom validation. Without validation, an editor can type a slug with capital letters or accents and Sanity does not stop them.
Hashnode and Dev.to
Both auto generate slugs the same way: strip accents, lowercase, replace spaces with hyphens, append a random string at the end (my-post-3a4b5c). The random suffix prevents collisions across the entire platform.
The gotcha: the random suffix means your slug looks generated, not curated. For a personal brand, this is mildly annoying. For a corporate blog, it is unprofessional. Both platforms let you edit the slug after publish, do it.
A practical migration routine
When migrating from one CMS to another:
- Export every URL from the old system.
- Run the source titles through the new system’s slug generator.
- Compare the two lists. Wherever they differ, set up a 301 redirect from old to new.
- For any URL that ends up shorter, longer, or restructured, redirect anyway. SEO equity loses 5 to 10 percent per redirect, but loses 100 percent on a 404.
- Test 50 random URLs on the live site after migration. If two of them 404, fix all of them.
The slug generator, the find and replace for batch redirect maps, and the text counter for sanity checking line counts all run in your browser. Slug behaviour is the kind of detail that nobody documents until it bites them. Knowing what each CMS does upfront saves the afternoon you would otherwise spend explaining to your team why their search traffic dropped.