How to automatically generate slugs for a large set of articles?

6 replies
Last updated: Oct 1, 2021
I have tons of articles, but they don't have slugs. I've now added a slug field to the schema, but it looks like I have to manually go in to every article, click generate, and then publish.
Is there a quicker way?
😄
AI Update

Great question! Yes, there's definitely a better way than manually clicking through every article. You can use Sanity's migration tooling to bulk-generate slugs for all your existing articles.

Create a Migration Script

First, generate a new migration using the CLI:

npx sanity@latest migration create "generate slugs for articles"

This will create a migration file in your migrations directory. Open the generated index.ts file and replace it with something like this:

import {defineMigration, at, setIfMissing} from 'sanity/migrate'

// Helper function to create URL-friendly slugs
function slugify(text: string): string {
  return text
    .toLowerCase()
    .replace(/[^\w\s-]/g, '') // Remove special characters
    .replace(/\s+/g, '-')      // Replace spaces with hyphens
    .replace(/--+/g, '-')      // Replace multiple hyphens with single
    .trim()
}

export default defineMigration({
  title: 'Generate slugs for articles',
  documentTypes: ['article'], // Replace with your document type
  
  migrate: {
    document(doc, context) {
      // Only generate if there's a title and slug is missing
      if (doc.title && !doc.slug?.current) {
        return [
          at('slug', setIfMissing({
            _type: 'slug',
            current: slugify(doc.title)
          }))
        ]
      }
      return []
    }
  }
})

Test It First (Dry Run)

Before making any changes, run it in dry-run mode to see what would happen:

npx sanity migration run generate-slugs-for-articles

This won't actually change anything - it just shows you what would be updated. Review the output to make sure it looks good!

Run the Migration

Once you're happy with the dry run results, execute it for real:

npx sanity migration run generate-slugs-for-articles --dataset production

Replace production with your dataset name (often production or development).

The migration toolkit automatically handles batching, rate limits, and gives you progress feedback. The setIfMissing operation ensures you won't overwrite any slugs that already exist, so it's safe to run even if some articles already have slugs.

Important Notes

  • The migration uses setIfMissing, so it won't overwrite existing slugs - only adds them where missing
  • You might want to add uniqueness checking if your slugs need to be unique (the basic example above doesn't handle duplicates)
  • Consider backing up your dataset first if you're working with production data
  • The migration is idempotent, meaning you can safely run it multiple times without creating problems

This approach is way better than clicking through hundreds of articles! 😄

Make a script that does it? You can adapt this and run
slugify
or something to set
slug.current
?
const buildPatches = docs =>
  docs.map(doc => ({
    id: doc._id,
    patch: {
      set: {'slug.current': slugify(doc.title)},
      // ifRevisionID: doc._rev
    }
  }))

could work! where can I read up on running these kinds of scripts?
sanity exec --with-user-token slug.js
ah great! thanks 🙂

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?