
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeYes, you can definitely replace an image that's referenced hundreds of times! Since the image asset is stored separately from your content documents (which only reference it), you have a couple of approaches:
The most reliable way is to upload your new image and then use Sanity's migration tooling to update all references across your dataset. This ensures all documents are updated consistently.
Here's how to do it:
1. First, upload your new image (either through Studio or programmatically) and note its asset ID.
2. Create a migration script:
npx sanity migration create replaceImageAsset3. Write the migration to find and replace all references:
import {defineMigration, at, set} from 'sanity/migrate'
const OLD_ASSET_ID = 'image-abc123...' // Your old image asset ID
const NEW_ASSET_ID = 'image-xyz789...' // Your new image asset ID
export default defineMigration({
title: 'Replace image asset across all documents',
migrate: {
document(doc, context) {
const mutations = []
// Helper function to recursively find and replace asset references
function findAndReplaceAsset(obj: any, path: string[] = []) {
if (!obj || typeof obj !== 'object') return
// Check if this is an asset reference
if (obj._ref === OLD_ASSET_ID) {
mutations.push(at([...path, '_ref'], set(NEW_ASSET_ID)))
}
// Recursively check nested objects and arrays
for (const [key, value] of Object.entries(obj)) {
if (key.startsWith('_')) continue // Skip system fields
findAndReplaceAsset(value, [...path, key])
}
}
findAndReplaceAsset(doc)
return mutations
}
}
})4. Test with dry-run first:
npx sanity migration run replaceImageAsset --dry-run5. Execute the migration:
npx sanity migration run replaceImageAssetIf you know exactly which fields contain the image (like mainImage or thumbnail), you can make the migration more targeted:
export default defineMigration({
title: 'Replace specific image field',
documentTypes: ['post', 'page'], // Only run on certain document types
migrate: {
document(doc, context) {
const mutations = []
// Check mainImage field
if (doc.mainImage?.asset?._ref === OLD_ASSET_ID) {
mutations.push(at('mainImage.asset._ref', set(NEW_ASSET_ID)))
}
// Check thumbnail field
if (doc.thumbnail?.asset?._ref === OLD_ASSET_ID) {
mutations.push(at('thumbnail.asset._ref', set(NEW_ASSET_ID)))
}
return mutations
}
}
})You might wonder if you can just delete the old asset and upload a new one with the same ID. Unfortunately, Sanity's asset IDs are system-generated based on the file content (using SHA-1 hashing), so you can't specify custom asset IDs during upload. The migration approach is the supported way to handle this.
--dry-run first to see what will change*[references("image-abc123...")]This approach is reliable, reversible (you can write another migration to switch back), and handles edge cases like nested references automatically.
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store