By default astro generates slug using filenames.

There are a few changes needed in order to generate the slug from the title field in frontmatter.

createSlug function #

This is a simple function which formats the title into a slug.

// src/lib/createSlug.ts
export default function (title: string) {
  return (
    title
      // remove leading & trailing whitespace
      .trim()
      // remove special characters
      .replace(/[^A-Za-z0-9 ]/g, '')
      // replace spaces
      .replace(/\s+/g, '-')
      // remove leading & trailing separtors
      .replace(/^-+|-+$/g, '')
      // output lowercase
      .toLowerCase()
  )
}

Slug Generation #

Instead of referencing post.slug we need to call createSlug referencing post.data.title.

// src/pages/blog/[...slug].astro
export async function getStaticPaths() {
  const posts = await getCollection("blog");
  return posts.map((post) => ({
-    params: { slug: post.slug },
+    params: { slug: createSlug(post.data.title) },
    props: post,
  }));
}
type Props = CollectionEntry<"blog">;

Blog Post Links #

Similar to above reference post.data.title using createSlug instead of post.slug

// src/pages/blog/index.astro
-  <a href={`/blog/${post.slug}/`}>{post.data.title}</a>
+  <a href={`/blog/${createSlug(post.data.title)}/`}>
+    {post.data.title}
+  </a>

Source #

The source for my astro blog is available on github.

blog-astro