---
title: "Trailing Slashes in Vue"
description: "Choose a trailing-slash policy for Vue routes. Match declared paths, preserve query values, and verify HTTP redirects and canonical URLs."
canonical_url: "https://nuxtseo.com/learn-seo/vue/routes-and-rendering/trailing-slashes"
last_updated: "2026-10-05"
---

> Index of every page on this site: [llms.txt](https://nuxtseo.com/llms.txt)

::key-takeaways
- Pick one URL format, with or without the trailing slash, and enforce it everywhere
- Prefer a permanent HTTP redirect, such as 301 or 308, for a permanent URL change. A Vue Router guard cannot set that status
- Keep canonical URLs, internal links, and sitemap URLs consistent with your chosen format
::

A trailing slash is the "/" at the end of a URL:

- With trailing slash: `/about/`
- Without trailing slash: `/about`

If both variants serve the same page, they can create duplicate URLs. Check your host's behavior:

- `/about` and `/about/` are distinct URLs. Google can select one canonical when they serve duplicate or similar content
- Duplicate variants can use additional crawl resources. See [crawling and indexing](https://nuxtseo.com/learn-seo/vue/controlling-crawlers)
- Analytics grouped by exact URL can split a page across variants

Pick one format and stick to it: [redirect](https://nuxtseo.com/learn-seo/vue/controlling-crawlers/redirects) the other, and set [canonical URLs](https://nuxtseo.com/learn-seo/vue/controlling-crawlers/canonical-urls) to match.

## Vue Router Configuration

### Enforcing Trailing Slashes

[Vue Router matches optional trailing slashes by default](https://router.vuejs.org/guide/essentials/route-matching-syntax.html#sensitive-and-strict-route-options). Its `strict` option requires the slash pattern declared in each path. It does not issue an HTTP redirect.

These are alternative router configuration excerpts for an installed Vue Router app. Import your app-owned About, Products, and BlogPost components before using them:

```ts
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    // Define all routes with trailing slashes
    { path: '/about/', component: About },
    { path: '/products/', component: Products },
    { path: '/blog/:slug/', component: BlogPost }
  ],
  strict: true // Enforce exact path matching
})
```

With `strict: true`, `/about` and `/about/` are treated as different routes.

### Removing Trailing Slashes

Alternatively, declare routes without trailing slashes. Reuse the imports above and your own page component imports:

```ts
const router = createRouter({
  history: createWebHistory(),
  routes: [
    // Define all routes without trailing slashes
    { path: '/about', component: About },
    { path: '/products', component: Products },
    { path: '/blog/:slug', component: BlogPost }
  ],
  strict: true
})
```

### Client-Side Redirects

After creating the no-slash router above, this guard normalizes client navigation. The commented alternative belongs to the slash-declared router. Keep the chosen policy and declared paths aligned:

```ts
router.beforeEach((to, from, next) => {
  // Remove trailing slashes
  if (to.path !== '/' && to.path.endsWith('/')) {
    next({ path: to.path.slice(0, -1), query: to.query, hash: to.hash })
    return
  }

  // Or add trailing slashes
  // if (to.path !== '/' && !to.path.endsWith('/')) {
  //   next({ path: to.path + '/', query: to.query, hash: to.hash })
  //   return
  // }

  next()
})
```

::warning
Vue Router navigation does not send an HTTP 301 or 308 response. [Google recommends server-side redirects when possible](https://developers.google.com/search/docs/crawling-indexing/301-redirects). Verify direct requests at the host as well as in-app navigation.
::

## Server-Side & Edge Redirects

Configure permanent URL redirects in your server or hosting platform when possible. Platform behavior differs: inspect its documented routing configuration instead of assuming a dashboard setting exists. Avoid redirect loops, preserve meaningful query parameters, and exclude assets or endpoints that need another policy.

Check both variants over HTTP, including query-bearing requests. The target must serve the intended page. A client guard cannot prove any of that behavior.

### Nginx

Use the [Nginx rewrite module documentation](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html) within your actual server configuration. Rewrite order, locations, existing directories, and arguments affect the result. Test your redirect and asset paths before deploying a rule.

### Apache

Use [Apache's redirect and remapping guidance](https://httpd.apache.org/docs/current/rewrite/remapping.html). Rules differ between server and directory contexts. Account for real directories and verify Location, query preservation, assets, and loop termination.

## Canonical URLs

In a component of an [Unhead-installed Vue app](https://unhead.unjs.io/docs/vue/head/guides/get-started/installation), set the page's preferred URL. This static example belongs only to the About page:

```vue
<script setup lang="ts">
import { useHead } from '@unhead/vue'

useHead({
  link: [
    {
      rel: 'canonical',
      href: 'https://example.com/about' // or /about/
    }
  ]
})
</script>
```

[Redirects and rel=canonical are canonicalization signals](https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls). They do not guarantee Google's selection. For SSR or generation, ensure your pipeline serializes the head into the response.

If you choose **no trailing slash**:

- Redirect `/about/` to `/about` with a permanent HTTP status, such as 301 or 308
- Page `/about` should have `<link rel="canonical" href=".../about">`{lang="html"}
- Test that the redirect terminates at the intended URL and preserves meaningful query values

Also make sure all internal links (`<RouterLink>`{lang="html"} or `<NuxtLink>`{lang="html"}) generate the correct format. If your canonical is `/about` but your menu links to `/about/`, you're sending mixed signals.

::checklist{#vue-trailing-slashes}
- Pick one URL format, with or without the trailing slash, for the whole site
- Match declared Vue Router paths to that policy; strict mode alone does not redirect
- Verify a permanent HTTP redirect, such as 301 or 308, separately from client navigation
- Set canonical tags that match your chosen format exactly
- Audit internal links (`<RouterLink>`{lang="html"}) so they match your canonical
- Keep sitemap URLs consistent with your chosen format
::

In Nuxt, site configuration can shape generated URLs. HTTP redirects require their own server or host policy: [Trailing Slashes in Nuxt](https://nuxtseo.com/learn-seo/nuxt/routes-and-rendering/trailing-slashes).

## Sitemap

See the full [sitemap](https://nuxtseo.com/sitemap.md) for all pages.
