skip to content
walterra.dev

Subscribe to walterra.dev

Handling Trailing Slashes in Astro Static Sites

/ 2 min read

Preface

This blog is built using Astro in a private github repo. On every update a Github Action runs the build and rsync’s the static pages to a dead simple shared hosting account I run now for roughly 20 years. In the golden days of blogging I ran PHP+MySQL sites there but nowadays it’s just static sites and some .htaccess spaghetti. I recently threw this blog into Google Search Console (previously known as Webmaster Tools) and noticed some problems getting the site properly indexed. One issue was the handling of trailing slashes. Here’s the setup I came up with to solve this, let’s hope it plays out nicely with page indexing.

The Challenge

Astro generates static sites by creating directories with index.html files. For example, a blog post URL like /blog/my-post is actually served from /blog/my-post/index.html. By default, this can lead to different versions of the URL being accessible:

  • /blog/my-post (clean URL)
  • /blog/my-post/ (directory with trailing slash)
  • /blog/my-post/index.html (full path)

Having all these versions accessible can cause SEO issues and confusion for users. We need to fix this and serve content properly when accessed without trailing slashes and redirect requests with trailing slashes to their non-trailing slash versions.

The Solution

1. Configure Astro

In your astro.config.ts or astro.config.mjs, set the trailingSlash option to 'never':

import { defineConfig } from "astro/config";
export default defineConfig({
trailingSlash: 'never',
// ... other config options
});

Search all your code for places that builds URLs and check it doesn’t add trailing slashes, I searched for /` and /‘.

2. Configure Apache (.htaccess)

Add these rules to your .htaccess file:

RewriteEngine On
# Remove trailing slash and redirect
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^(.+)/$ [NC]
RewriteRule ^ %1 [R=301,L]
# Handle directory access without trailing slash
DirectorySlash Off
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_FILENAME}/index.html -f
RewriteRule (.*) $1/index.html [L]

The first rule block catches any URL with a trailing slash and redirects it to the non-trailing slash version using a 301 (permanent) redirect.

The second rule block handles the internal rewriting of clean URLs to their corresponding index.html files:

  • DirectorySlash Off prevents Apache from automatically adding trailing slashes to directories
  • The conditions ensure we only rewrite requests that:
    • Are for directories
    • Don’t end with a slash
    • Have an index.html file in them

Testing

After implementing these changes, verify that:

  1. URLs without trailing slashes work correctly
  2. URLs with trailing slashes redirect to their non-trailing slash versions
  3. All content is served properly
  4. No redirect loops occur

Hope that helps!

References


Comments powered by Talkyard.