Trailing Slashes in Vue · Nuxt SEO

-
-
-
-

[1.4K](https://github.com/harlan-zw/nuxt-seo)

[Nuxt SEO on GitHub](https://github.com/harlan-zw/nuxt-seo)

Learn SEO

Master search optimization

Nuxt

 Vue

-
-
-
-
-
-
-

-
-
-
-
-
-
-

-
-
-

-
-
-
-
-
-
-
-
-
-
-

-
-
-

-
-
-
-
-
-
-
-
-

1.
2.
3.
4.
5.

# Trailing Slashes in Vue

Trailing slashes can cause duplicate content issues. Here's how to handle them in Vue Router.

[![Harlan Wilton](https://avatars.githubusercontent.com/u/5326365?v=4)Harlan Wilton](https://x.com/harlan-zw)6 mins read Published Nov 6, 2024 Updated Jan 29, 2026

What you'll learn

- **Consistency is King**: Pick one format (slash or no-slash) and enforce it everywhere.
- **Server/Edge Redirects**: Always use 301 redirects at the server or edge layer. Client-side redirects are too late for SEO.
- **Canonical Tags**: Your canonical URL must strictly match your chosen format.

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

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

While trailing slashes don't directly impact SEO rankings, they can create technical challenges:

1. **Duplicate Content**: When both `/about` and `/about/` serve the same content without proper canonicalization, search engines have to choose which version to index. While Google is generally good at figuring this out, it's better to be explicit.
2. **Crawl Budget**: On large sites, having multiple URLs for the same content can waste your.
3. **Analytics Accuracy**: Different URL formats can split your analytics data, making it harder to track page performance.

The solution is simple: pick one format and stick to it by

 the other and set

.
## [Vue Router Configuration](#vue-router-configuration)

### [Enforcing Trailing Slashes](#enforcing-trailing-slashes)

Vue Router has a `strict` mode that enforces exact path matching:

```
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](#removing-trailing-slashes)

To remove trailing slashes consistently:

```
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](#client-side-redirects)

Add a navigation guard to redirect inconsistent URLs:

```
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()
})
```

**Important:** Client-side redirects don't send proper HTTP 301 status codes to search engines. Use server-side redirects for SEO.

## [Server-Side & Edge Redirects](#server-side-edge-redirects)

For proper SEO, redirects must happen **before** the Vue app loads.

### [Edge / Platform Config (Recommended)](#edge-platform-config-recommended)

Modern hosting platforms (Cloudflare Pages, [Vercel](https://vercel.com), [Netlify](https://netlify.com)) often have a "Trailing Slash" setting in their dashboard or config file (e.g., `netlify.toml`, `vercel.json`). **Use this first.** It handles the redirect at the network edge, which is the fastest method.

### [Nginx](#nginx)

Remove trailing slashes:

```
rewrite ^/(.*)/$ /$1 permanent;
```

Add trailing slashes:

```
rewrite ^([^.]*[^/])$ $1/ permanent;
```

### [Apache](#apache)

Remove trailing slashes:

```
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [R=301,L]
```

Add trailing slashes:

```
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1/ [R=301,L]
```

## [Canonical URLs](#canonical-urls)

Set canonical URLs to indicate your preferred URL format:

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

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

### [Canonicalization Strategy](#canonicalization-strategy)

Don't just rely on redirects. Your `rel="canonical"` tag is a strong hint to Google about which version you prefer.

If you choose **no trailing slash**:

- Redirect `/about/` -> `/about` (301)
- Page `/about` should have `<link rel="canonical" href=".../about">`
- Page `/about/` (before redirect) should _technically_ also point to `/about` (but the 301 handles this).

**Crucially**, ensure all internal links (`<RouterLink>` or `<NuxtLink>`) generate the correct format. If your canonical is `/about` but your menu links to `/about/`, you are sending mixed signals.

## [Best Practices](#best-practices)

1. **Choose One Format**: Pick with or without trailing slashes and stick to it site-wide.
2. **Edge/Server Redirects**: Use 301 redirects at the network level.
3. **Canonical Tags**: Always set canonical URLs to your preferred format.
4. **Internal Links**: Audit your navigation to ensure it matches your canonicals.
5. **Sitemap**: Use consistent URLs in your sitemap.

## [Using Nuxt?](#using-nuxt)

If you're using Nuxt, it provides automatic trailing slash handling through site config.

---

On this page

- [Vue Router Configuration](#vue-router-configuration)
- [Server-Side & Edge Redirects](#server-side-edge-redirects)
- [Canonical URLs](#canonical-urls)
- [Best Practices](#best-practices)
- [Using Nuxt?](#using-nuxt)

[GitHub](https://github.com/harlan-zw/nuxt-seo) [ Discord](https://discord.com/invite/275MBUBvgP)

###

-
-

Modules

-
-
-
-
-
-
-
-
-

###

-
-
-

###

Nuxt

-
-
-
-
-

Vue

-
-
-
-
-
-
-
-

###

-
-
-
-
-
-
-
-
-
-

Copyright © 2023-2026 Harlan Wilton - [MIT License](https://github.com/harlan-zw/nuxt-seo/blob/main/license) · [mdream](https://mdream.dev)