How to manage 70+ redirects from Sanity CMS instead of hardcoding in next.config.js?

7 replies
Last updated: Jan 31, 2022
Hey all,I’m working on a blog build replacing a Squarespace blog and its URL structure was
<http://blog.domain.com/|blog.domain.com/>
With this new build, they want the domain to be
<http://domain.com/blog/|domain.com/blog/>
with single posts having their slugs following.
I’m planning out how I will handle redirects and wanted to get your thoughts. The project uses NextJS and from my understanding I should handle
redirects /rewrites in the
next.config.js
file located in the root. However, I’ve got at least 70 redirects, so it’d be amazing to be able to provide that data in Sanity and just map over it rather than hardcode the data.
Do you know if that’s possible? Do you have any better ideas?
AI Update

Great question! Yes, you can absolutely manage redirects from Sanity instead of hardcoding 70+ entries in your next.config.js. Here's how I'd approach this:

Storing Redirects in Sanity

Create a schema for redirects in your Studio. For redirect management, string fields are the correct choice since you're storing complete URL paths, not generating slugs from other fields:

export default {
  name: 'redirect',
  title: 'Redirects',
  type: 'document',
  fields: [
    {
      name: 'source',
      type: 'string',
      title: 'Source Path',
      description: 'The old URL path (e.g., /old-post-slug)',
      validation: Rule => Rule.required(),
    },
    {
      name: 'destination',
      type: 'string',
      title: 'Destination Path',
      description: 'The new URL path (e.g., /blog/new-post-slug)',
      validation: Rule => Rule.required(),
    },
    {
      name: 'permanent',
      type: 'boolean',
      title: 'Permanent Redirect (301)',
      description: 'Use 301 for permanent, 302 for temporary',
      initialValue: true,
    },
  ],
}

Note: The slug field type is designed for generating URL-friendly identifiers from source fields (like titles) and is best used for document permalinks. For redirect management where you're storing complete path strings, regular string fields are more appropriate.

Fetching Redirects in next.config.js

In your next.config.js, fetch the redirects from Sanity at build time:

const client = require('@sanity/client')

const sanityClient = client({
  projectId: 'your-project-id',
  dataset: 'production',
  apiVersion: '2024-01-01',
  useCdn: false, // Important: always get fresh data at build time
})

module.exports = async () => {
  const redirects = await sanityClient.fetch(`
    *[_type == "redirect"] {
      source,
      destination,
      permanent
    }
  `)

  return {
    async redirects() {
      return redirects.map(redirect => ({
        source: redirect.source,
        destination: redirect.destination,
        permanent: redirect.permanent ?? true,
      }))
    },
  }
}

Handling Subdomain to Path Migration

For your specific case (blog.domain.com → domain.com/blog), you can use a wildcard pattern with a has condition to handle the entire subdomain migration:

async redirects() {
  // Catch-all for subdomain to new path structure
  const subdomainRedirect = {
    source: '/:path*',
    destination: '/blog/:path*',
    permanent: true,
    has: [
      {
        type: 'host',
        value: 'blog.domain.com',
      },
    ],
  }

  // Individual redirects from Sanity for any custom mappings
  const customRedirects = redirects.map(redirect => ({
    source: redirect.source,
    destination: redirect.destination,
    permanent: redirect.permanent ?? true,
  }))

  return [subdomainRedirect, ...customRedirects]
}

Important Considerations

Rebuild Requirement: Changes to next.config.js require a rebuild since redirects are evaluated at build time. When you update redirects in Sanity, you'll need to trigger a new deployment. The modern way to handle this is with Sanity Functions - you can create a function that listens for changes to redirect documents and triggers your hosting platform's build hook automatically.

Caching: Always use useCdn: false when fetching redirects at build time to ensure you get the latest data.

Alternative for Real-Time Updates: If you need redirects to update without rebuilding, you can implement them in Next.js middleware instead. The middleware fetches from Sanity on each request, but this has performance implications since it runs server-side for every navigation.

Pattern Matching Optimization: Since you're migrating from a subdomain to a path structure, you might not need all 70 individual redirects! The wildcard pattern /:path* with the has condition can handle the entire subdomain migration automatically. You'd only need individual redirect documents in Sanity for posts that also changed their slug during the migration.

This approach gives you the flexibility to manage redirects through your CMS while keeping them performant at the edge with Next.js!

Show original thread
7 replies
Hi Dani. Will your blog posts be keeping the same slugs? If they are, the best option for you may be to setup a redirect from
<http://blog.domain.com/:slug|blog.domain.com/:slug>
to
<http://domain.com/blog/:slug|domain.com/blog/:slug>
. This would save you from having to maintain a list of individual redirects.
Hey Ash, thanks for responding. It looks like some of the Squarespace posts have slugs like this
/blog/title-of-post
and others are like this
/blog/2021/8/30/title-of-blog
. Since our new slugs are going to use this pattern
/blog/title-of-post
I don’t think a simple redirect rule will cover it.
Next's
redirects()
function is async, so you can do a GROQ query to fetch your redirects from Sanity. There are a couple of ways you could structure this in sanity:
1. Add a field for the "old path" to your blog post document schema.
2. Add a settings page for adding
any redirect (e.g https://www.sanity.io/docs/create-a-link-to-a-single-edit-page-in-your-main-document-type-list ).Whichever way you choose to structure it, you will be able to do a single GROQ query inside Next's
redirects()
function and convert your redirect data into the object expected by Next.
I hope this helps. Please let us know if you have any other questions!
Ash, this was exactly the sort of tip I was hoping for.
For future reference, I did some Googling and found this blog post illustrating your suggested solution #2:
https://maxkarlsson.dev/blog/redirects-with-sanity-next-js-and-vercel
Do you potentially have any references illustrating solution #1?
Ash, this was exactly the sort of tip I was hoping for.
For future reference, I did some Googling and found this blog post illustrating your suggested solution #2:
https://maxkarlsson.dev/blog/redirects-with-sanity-next-js-and-vercel
Do you potentially have any references illustrating solution #1?
Sure!
For example, you could use a schema like this for your blog posts:


{
  title: 'Article',
  name: 'article',
  type: 'document',
  fields: [
    {
      title: 'Title',
      name: 'title',
      type: 'string',
    },
    {
      title: 'Slug',
      name: 'slug',
      type: 'slug',
    },
    {
      title: 'Old Path',
      name: 'oldPath',
      type: 'string',
    },
  ],
},
You could then use a GROQ query like this to fetch all of the redirects and assemble them into the shape expected by Next.js:


*[_type == "article"]{
  "source": oldPath,
  "destination": "/blog/" + slug.current,
  "permanent": true
}
user E
thanks for that insight. I’ll let you know how it goes

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?