Diego Betto's Blog
Photo by Firmbee.com on Unsplash

October 10, 2024 · 3 min di lettura

Astro trailing slashes and canonical tags

How to correctly set slashes in URLs and canonical HTML tags for Astro-based applications

Condividi:XLinkedInFacebookWhatsApp

What trailing slashes are

When building web applications we often have to deal with URL formatting. One of the most debated topics in SEO is whether to include or drop trailing slashes — the slash at the end of an address.

To be concrete, you often have to decide and set up addresses in this format

https://www.domain.tld/path

or in the format with a trailing slash

https://www.domain.tld/path/

The difference might look minor but it isn’t. Let’s understand why, then look at how to configure Astro to use trailing slashes or not.

Trailing slash problems: duplicate addresses and what canonicals are

Let’s look at a few problems a mishandled trailing slash setup can cause.

If a website accepts both addresses with and without a trailing slash, the same page becomes reachable from two different addresses. It’s usually good practice to set up a redirect from one version to the other. If you don’t, Google Search Console may show you an “Alternate page with proper canonical tag” issue.

Given equal content, Google tries to elect one page as the “official” one. When it mistakenly finds two identical pages with different addresses, it tries to drop from its index the pages whose canonical tag isn’t valid.

ℹ️ What is canonicalization?

Canonicalization is the process of selecting the canonical URL representative of a piece of content. As a result, a canonical URL is the URL of a page that Google has chosen as the most representative among a set of duplicate pages. This process, often called deduplication, lets Google show only one version of the content in search results, instead of duplicates.

link to Google Search Central

In HTML it’s a tag in the HEAD that indicates the official address of that content, for example

<link rel="canonical" href="https://diegobetto.com/en/astro-trailing-slash-canonical-urls" />

is the canonical tag of the page you’re reading.

The situations you can typically run into are:

  • two pages with different URLs, two different canonical tags, and the same content
  • two pages with different URLs, two identical canonical tags, and the same content
  • pages whose canonical differs from the actual address (the canonical has a trailing slash but the address doesn’t, or vice versa)

These situations create confusion, and Google or search engines in general end up deciding which one to exclude.

How to solve the problem with Astro

If you’re building an application with Astro, there are a couple of places where you can control the generated addresses and routes. In astro.config.(ts|js) there’s an option for trailing slashes

export default defineConfig({
  trailingSlash: "never",
  // the rest of the config...
});

The available options are:

  • ‘always’ - Only URLs that include a trailing slash (e.g.: “/foo/”)
  • ‘never’ - URLs that never include a trailing slash (e.g.: “/foo”)
  • ‘ignore’ - Match URLs regardless of whether a trailing “/” exists or not

More information on the official Astro.build site

If you need to, remember you can also use the redirect options

{
  redirects: {
    '/old': '/new',
    '/blog/[...slug]': '/articles/[...slug]',
  }
}

More on redirects, again, in the Astro docs

Bonus: setting up trailing slashes on Vercel

If you use Vercel, one more thing you can do is create a vercel.json file, if you don’t already have one, and add this configuration to it, adapting it to your needs.

{
  "trailingSlash": false
}

This sets up how Vercel handles addresses with or without a trailing slash.

Bonus tip: check your code

It sounds obvious, but also check the addresses you set in your code through components like <Link /> or <a> tags. They must match the address logic you’ve chosen for your site. Same goes for the addresses in your site’s sitemap — verify they match.

One extra redirect for a wrong trailing slash is a millisecond lost before the page even starts loading — small, but the same kind of detail I cover in the article on Core Web Vitals.

Happy coding! 😄

Condividi:XLinkedInFacebookWhatsApp