How to debug intermittent Netlify redirects from Sanity CMS?

21 replies
Last updated: Dec 2, 2025
Hey there,
I’m wondering if anyone has any advice on redirects. I followed the advice in the
help channel, and it was really good information. I can’t find the thread now, though.
Anyway, I leaned very heavily on
user L
’s gist , and my code looks like this:

redirect.js

export default {
    title: "Redirect",
    name: "redirect",
    // __experimental_actions: ['update', 'create', 'delete', 'publish'],
    type: "document",
    fields: [
        {
            title: "Internal Name",
            name: "internalName",
            type: "string",
            validation: Rule => Rule.required(),
        },
        {
            title: "Match Rule",
            description:
                "The URL path to match. This is the "from" portion of the redirect. A "splat" (*) can be used to match any additional characters at the end of the line (e.g. `/blog/*`).",
            name: "rule",
            type: "string",
            validation: Rule =>
                Rule.required().regex(/^\//, { name: "Must start with a `/`" }),
        },
        {
            title: "Redirect Target",
            description:
                "The destination for the redirect. If a "splat" (*) was used in the match rule, it can be expanded in the target using `:splat` (e.g. `/blog/:splat`).",
            name: "target",
            type: "string",
            validation: Rule => Rule.required().regex(/^(\/|https?:\/\/)/),
        },
        {
            title: "Redirect Type",
            description:
                "Both temporary and permanent redirects can be internal or external links. Rewrites can only be internal (i.e. to another page that is built in Sanity).",
            name: "statusCode",
            type: "string",
            options: {
                list: [
                    { title: "Temporary (302)", value: "302" },
                    { title: "Permanent (301)", value: "301" },
                    { title: "Rewrite (200)", value: "200" },
                ],
            },
            validation: Rule => Rule.required(),
        },
    ],
    preview: {
        select: {
            title: "internalName",
            rule: "rule",
            target: "target",
            statusCode: "statusCode",
        },
        prepare: ({ title, rule, target, statusCode }) => ({
            title,
            subtitle: `${rule} ${target} ${statusCode}`,
        }),
    },
}

gatsby-node.js

const fs = require('fs')
const path = require('path')

exports.onPostBuild = ({ graphql }) => {
	graphql(`
		{
			redirects: allSanityRedirect {
				nodes {
					target
					rule
					statusCode
				}
			}
		}
	`).then(({ data }) => {
		const redirectData = data.redirects.nodes
			.map(({ rule, target, statusCode }) => `${rule} ${target} ${statusCode}`)
			.join('\n')

		console.log('*********************************************')
		console.log('redirectData: ', redirectData)
		console.log('*********************************************')
		return fs.appendFile(path.resolve(__dirname, 'public/_redirects'), redirectData, (err) => {
			if (err) throw err
			console.log('redirect error:', err)
		})
	})
}
When I deploy this to Netlify,
sometimes the redirect rules are processed, and other times it’s completely ignored. I can’t figure out what changes from one deploy to the next. There is a console.log that prints out the redirects, and they also show in the console regardless of whether or not the redirects are actually created. Can anyone see anything wrong with the code, or help me to see what I’m missing?
AI Update

This is really a Gatsby and Netlify deployment question rather than a Sanity-specific issue - your Sanity schema and data fetching are working correctly (as evidenced by your console logs showing the redirect data). The intermittent behavior you're seeing is happening during the Gatsby build process when writing to Netlify's _redirects file.

Since this is about Gatsby's build lifecycle and Netlify's redirect handling rather than Sanity's functionality, I'd recommend posting this question in the Gatsby Discord or the Netlify Support Forums where you'll find folks with deep expertise in those specific build and deployment issues.

From a Sanity perspective, your redirect document schema looks solid and follows good patterns - you're validating the fields appropriately and the GraphQL query is correctly fetching the data you need. The issue is entirely downstream in how Gatsby processes that data during the build.

A couple of potential issues I can spot in your gatsby-node.js code that might be causing the intermittent behavior:

  1. Async handling: Your graphql() call returns a promise, but onPostBuild isn't waiting for it. Try returning the promise chain so Gatsby knows to wait for it to complete before finishing the build.

  2. fs.appendFile vs fs.writeFile: You're using appendFile, which adds to the end of an existing file. If the _redirects file already exists from a previous build (which it might in certain caching scenarios), you could be appending duplicate rules. Consider using fs.writeFile instead to overwrite the file completely.

Here's a revised version that addresses these issues:

exports.onPostBuild = ({ graphql }) => {
  return graphql(`
    {
      redirects: allSanityRedirect {
        nodes {
          target
          rule
          statusCode
        }
      }
    }
  `).then(({ data }) => {
    const redirectData = data.redirects.nodes
      .map(({ rule, target, statusCode }) => `${rule} ${target} ${statusCode}`)
      .join('\n')

    console.log('Writing redirects:', redirectData)
    
    return fs.promises.writeFile(
      path.resolve(__dirname, 'public/_redirects'), 
      redirectData
    )
  })
}

Note the key changes: returning the promise chain and using writeFile instead of appendFile. This should give you more consistent behavior across deployments.

But again, for the deeper Gatsby build lifecycle questions, the Gatsby community will be your best resource for troubleshooting plugin execution order and build caching issues.

Show original thread
21 replies

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?