Index of every page on this site: llms.txt

Trailing Slashes in Nuxt

Choose a trailing slash convention, configure NuxtLink and canonical URLs, and test server redirects.
Harlan Wilton5 mins read Published Updated
What you'll learn
  • Use trailing slashes for static file servers, legacy URL migrations, or CMS conventions
  • Configure NuxtLink globally with experimental.defaults.nuxtLink.trailingSlash
  • Set site.trailingSlash for SEO modules, then verify links and redirects separately

A trailing slash is the / at the end of a URL. /about/ has one, /about doesn't. Both can serve identical content, and that's the problem.

nuxt.config.ts
export default defineNuxtConfig({
  site: {
    trailingSlash: true // URL preference for modules that use Site Config
  }
})

Why Enable Trailing Slashes

Most Nuxt sites don't need trailing slashes. But there are cases where you'll want them:

  • Static file servers such as Apache, Nginx, and S3 treat trailing slashes as directories, serving /about/ as /about/index.html. Skip the slash and some of them return 404s or need extra config
  • If you're migrating from WordPress, Rails, or another legacy CMS that used trailing slashes, matching the existing format avoids mass redirects
  • If your team uses a trailing-slash convention in CMS path data, apply that convention consistently in the app
  • Team convention: some developers use the trailing slash to visually mark a URL as a section

If none of these apply, stick with Nuxt's default: no trailing slashes.

NuxtLink has built-in trailing slash support. Set it globally or per-link.

Apply trailing slashes to all internal links:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    defaults: {
      nuxtLink: {
        trailingSlash: 'append' // or 'remove'
      }
    }
  }
})

Every <NuxtLink to="/about"> now renders as /about/.

Override the global setting on specific links:

<template>
  <!-- Forces trailing slash regardless of global config -->
  <NuxtLink to="/api/docs" trailing-slash="append">
    API Docs
  </NuxtLink>

  <!-- Removes trailing slash regardless of global config -->
  <NuxtLink to="/blog" trailing-slash="remove">
    Blog
  </NuxtLink>
</template>

Use this for external integrations or API routes that require a specific format.

SEO Configuration

If /about and /about/ serve equivalent content, they create duplicate URLs. Google can consolidate them automatically. Consistent redirects and canonical signals express your preferred URL.

Configure three parts:

  1. Consistent internal links
  2. Correct canonical URLs
  3. Redirects for the wrong format

Manual Setup

Without Nuxt SEO, configure each piece separately:

nuxt.config.ts
export default defineNuxtConfig({
  // 1. NuxtLink trailing slashes
  experimental: {
    defaults: {
      nuxtLink: {
        trailingSlash: 'append'
      }
    }
  },
})

This canonical example covers parameter-free pages. If a query parameter changes content, preserve it according to your URL policy, including pagination:

<script setup lang="ts">
const route = useRoute()

useHead(() => ({
  link: [{ rel: 'canonical', href: `https://example.com${route.path}${route.path.endsWith('/') ? '' : '/'}` }]
}))
</script>

This works but doesn't scale.

Nuxt SEO Setup

Nuxt SEO shares the URL preference with its SEO modules:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/seo'],
  site: {
    url: 'https://example.com',
    trailingSlash: true
  }
})

Verify the configured modules' output:

Nuxt SEO 
   
The all-in-one module that brings it all together.

Redirects for Wrong Format

Even with correct internal links, external sites and old bookmarks may use the wrong format. Set up server-side redirects.

Using Route Rules

Do not assume an exact /about rule excludes /about/. Nitro can match both and redirect the destination to itself. Use pathname-aware middleware below, or your host's tested URL normalization.

Using Server Middleware

This example normalizes non-file page paths. Confirm these exclusions match your application. It preserves the query string and leaves the slash destination unchanged:

server/middleware/trailing-slash.ts
export default defineEventHandler((event) => {
  const url = getRequestURL(event)
  const path = url.pathname
  // Skip API routes and files with extensions
  if (path === '/api' || path.startsWith('/api/') || path.includes('.'))
    return

  // Redirect non-trailing to trailing
  if (!path.endsWith('/')) {
    return sendRedirect(event, `${path}/${url.search}`, 301)
  }
})

Static Hosting and Prerendering

When prerendering, Nuxt generates /about as /about/index.html by default. Your static host determines whether /about redirects to /about/. Check the deployed response.

If you want trailing slashes, this is correct behavior.

Set autoSubfolderIndex: false to generate /about.html instead. This changes output layout; your host still controls URL redirects:

nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    prerender: {
      autoSubfolderIndex: false
    }
  }
})

Checklist

Checklist
  • Decide on trailing slashes or no trailing slashes for the whole site
  • Set site.trailingSlash for SEO modules; configure and verify NuxtLink and redirects
  • Verify wrong-format URLs redirect once, preserve queries, and terminate at a successful page
  • Confirm canonical URLs match your chosen format
  • Check prerendered output matches your trailing slash setting (autoSubfolderIndex)
Was this page helpful?