How to Replace Types on Images without Re-adding Each Image for Every Object/Document

1 replies
Last updated: Jul 8, 2021
I have some objects with images, but i figured i should have made a custom image object, which supports things like alt text. Is there a way to not having to re add the images for every object/document where i want to replace
type: 'image'
with
type: 'customImage'
?
AI Update

Good news! You don't have to re-add all your images. You can migrate your existing image data to use the new custom image type through a migration script.

Since Sanity's backend is schemaless, your existing image data is still there even after you change the schema. The key is to write a migration script that transforms your existing documents to add the new fields (like alt text) while preserving the existing image references.

Here's the general approach:

  1. Update your schema to use your new customImage type where you previously had type: 'image'

  2. Write a migration script that:

    • Queries all documents with the old image structure
    • Transforms them to match your new custom image structure
    • Preserves the existing _ref to the image asset

Here's an example migration script:

import {getCliClient} from 'sanity/cli'

const client = getCliClient()

const fetchDocuments = () => 
  client.fetch(`*[_type == "yourDocType" && defined(yourImageField._ref)]`)

const buildPatches = (docs) =>
  docs.map((doc) => ({
    id: doc._id,
    patch: {
      set: {
        yourImageField: {
          _type: 'customImage',
          asset: {
            _type: 'reference',
            _ref: doc.yourImageField._ref // Preserve existing image reference
          },
          alt: '' // Add default alt text, or derive from existing data
        }
      }
    }
  }))

const createTransaction = (patches) =>
  patches.reduce(
    (tx, patch) => tx.patch(patch.id, patch.patch),
    client.transaction()
  )

const migrateNextBatch = async () => {
  const documents = await fetchDocuments()
  const patches = buildPatches(documents)
  if (patches.length === 0) {
    console.log('No more documents to migrate!')
    return null
  }
  console.log(`Migrating batch:\n %s`, patches.map((patch) => patch.id).join('\n'))
  const transaction = createTransaction(patches)
  await transaction.commit()
  return migrateNextBatch()
}

migrateNextBatch().catch((err) => {
  console.error(err)
  process.exit(1)
})

Key principles from Sanity's migration best practices:

  • Idempotent scripts: Make sure you can run the script multiple times safely
  • Incremental approach: Test on a few documents first, then scale up
  • Preserve asset references: The _ref to your image asset stays the same, so you're not re-uploading images

You can also use the deprecated field feature to mark old fields during the transition period, so they're visible on documents that still have them but hidden on new documents.

For more complex migrations, check out the schema and content migrations documentation and the handling schema changes course.

Show original thread
1 reply
Yeah
user A
, that’s a good point. If you just add the
fields
to the image you can edit them in the studio and preserve the images without having to patch.

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?