Automatic management of slug redirects?

Record slugs are often used as URLs, but they can also be changed by editors. For example, my-blog-post might become new-title after a few weeks after publishing. In this case, it would be nice for users to have a redirect from my-blog-post to new-title.

However, it’s impractical to manually manage these sorts of redirects. As the number of records, slugs, editors pile up over time, it becomes harder to harder to manage. This is especially true if a redirect chain is created, which is common when my-blog-post goes to new-title and then new-title goes to even-newer-title and so forth.

In a traditional (headful? headed? capitated?) CMS, this would be handled by a plugin like Redirect manager for Wordpress or Pathauto for Drupal.

In a headless Jamstack, it’s more complicated because the host (say, Vercel) needs to get that information from a framework’s redirect file (like Next.js rewrites), but there is no easy way to query DatoCMS for a record’s slug revision history.

As a feature request, would it be possible to have DatoCMS record slug changes somewhere, and make it exportable to various frameworks?

An examples of how this could work (doesn’t have to be this way, just an example): In the Settings menu, there is a new “Slug Changes” section. Any time a slug is changed in a record, that change will be recorded in a table, with old-slug, new-slug, a timestamp, and the record ID and current slug (at the time of lookup). Maybe something like this mockup:

Then this table can either be exported to simple .CSV or .JSON, or maybe even exported straight into a rewrites file format for common frameworks/hosts (nginx, next.js, gatsby, etc.), so a new build can make all the old slugs go to the right places. Records that were deleted altogether would just 404.

Just as an aside, FYI, right now we are working around this need through a custom, hybrid slug & ID URL redirection scheme.

The URLs we use are a combination of slugs and also the record ID. So instead of /products/yellow-tee-shirt, we use /products/yellow-tee-shirt__482849.

Anything ending in ___482849 (the record ID) will get canonicalized and redirected to the newest slug. If the slug is renamed to mens-large-yellow-tee-shirt, the old link will automatically redirect to /products/mens-large-yellow-tee-shirt___482849 instead. In fact none of the text really matters for routing; it’s just there for human readability and SEO. The ID at the end is how our routing system actually finds the right record.

If the ID is not there, the system will attempt to look up that record by its slug only, and if it finds it, it will again redirect to the canonical version with the ID.

In this way, we don’t have to record old slugs at all. Anything ending in ___482849 will always get redirected to the latest canonical version. Whether it’s an older slug or complete gibberish like /products/this-is-a-fake-product___482849, it’ll still redirect. As a nice side effect, this also handles nested tree models pretty well, since the ___482849 query will look up its parent slugs and re-create the latest folder structure automatically.

Getting all this to work required a lot of tinkering with Next.js’s rewrites and routing system. Let me know if anyone wants more information…

It’s a pretty ugly and inelegant system, but it’s better than nothing for now. Still, a proper redirects management solution would be better :slight_smile:

2 Likes