How I fixed the trailing slash in Netlify rewrites
By Flavio Copes
How I fixed broken relative links and images caused by missing trailing slashes in Netlify rewrites, with a tiny script and a Netlify Edge Function alternative.
Netlify has this great feature that allows me to create a number of duplicate pages, by adding them into the _redirects file in the public root of the project (public/_redirects in Hugo, for example).
I use it to power some of my websites.
If I have a bunch of pages under content/original, by writing:
/copy/* /original/:splat 200
I can call the URL
/copy
and when I access https://mysite.com/copy I have the content stored inside https://mysite.com/original, and the URL does not change. It’s not a redirect (despite the _redirects file name), it’s a rewrite because I used the 200 code at the end. Had I used 301, that would have been a 301 redirect.
If you want to check your rules before deploying, I built a free redirects simulator where you paste your _redirects file and test paths against it.
Anyway, the problem I stumbled upon is this: Netlify normalizes the URL before the redirect rules run, so /copy and /copy/ match the same rule and you cannot use _redirects to add the trailing slash. If you use relative URLs for images and links, the version without the slash breaks them: links lead to 404s and images don’t load.
Netlify’s Pretty URLs setting adds the slash for real pages in your build (/about becomes /about/). It did nothing for this rewrite, since there is no real /copy/ page.
I looked for a solution in my static site generator, to see if it could replicate redirects in another way, but in the end my solution was client side.
And very simple.
I added this JavaScript snippet at the bottom of my pages:
<script>
(function() {
if (!location.href.endsWith('/')) {
window.location = location.href + '/'
}
}())
</script>
And the page now if there’s no trailing slash will immediately reload with the slash appended at the end.
The process is so quick it’s almost invisible to the user.
A cleaner fix: an Edge Function
Today Netlify has Edge Functions, and they run before the redirect rules. You can redirect to the slash version before anything renders, with no reload in the browser.
Create netlify/edge-functions/trailing-slash.js:
export default async (request, context) => {
const url = new URL(request.url)
const lastSegment = url.pathname.split('/').pop()
if (!url.pathname.endsWith('/') && !lastSegment.includes('.')) {
url.pathname += '/'
return Response.redirect(url.toString(), 301)
}
return context.next()
}
export const config = { path: '/*' }
The includes('.') check leaves files like /style.css or /logo.png alone. Everything else without a slash gets a 301 to the slash version, so /copy becomes /copy/ and relative images and links resolve again.
The inline config is enough. You can also declare the function in netlify.toml if you need to control the order it runs in.
Want me to talk about your product? You can sponsor this site.
Related posts about services: