CoursesHandling schema changes confidentlyWriting a content migration
Certification
Sanity developer certification
Track
Sanity developer essentials

Handling schema changes confidently

Lesson
5

Writing a content migration

Use Sanity CLI to create a new content migration. Adapt the migration script for your use case.

Log in to mark your progress for each Lesson and Task

While the current solution with the adapted GROQ query and the deprecated field works, having two field names for the same type of content can be confusing. Imagine you want to make a new filter on the home page. You would have to take both field names into account. For changes like these, it might be a good idea to move the legacy content over to the new field and, in this case, remove the old field completely so we can also keep the document form nice and tidy.

Since the front end query now works with both fields, you can even migrate content against the production dataset without any downtime or disruption.

The Sanity CLI contains helpful guidance and templates to create content migration scripts.

Inside your Sanity Studio, create a new content migration
npx sanity@latest migration create "Replace event type with event format"

The CLI will prompt with some questions; answer the following (you can always change this in code after):

Type of documents to migrate: event
Select a template: Rename a field

The CLI should now have made a new folder in your Studio project called migrations with a content migration script inside replace-event-type-with-event-format/index.ts.

Open the content migration script in your code editor

In fact, the CLI has done most of the job already. But let’s unpack what’s going on.

migrations/replace-event-type-with-event-format/index.ts
import {defineMigration, at, setIfMissing, unset} from 'sanity/migrate'
const from = 'oldFieldName'
const to = 'newFieldName'
export default defineMigration({
title: 'Replace event type with event format',
documentTypes: ["event"],
migrate: {
document(doc, context) {
return [
at(to, setIfMissing(doc[from])),
at(from, unset())
]
}
}
})

You can see that the script imports a couple of functions from sanity/migrate and has a default export called defineMigration.

Change the from and to variables to reflect the schema change you want to do.

Set from to the value eventType
Set to to the value format
migrations/replace-event-type-with-event-format/index.ts
import {defineMigration, at, setIfMissing, unset} from 'sanity/migrate'
const from = 'eventType'
const to = 'format'
export default defineMigration({
title: 'Replace event type with event format',
documentTypes: ["event"],
migrate: {
document(doc, context) {
return [
at(to, setIfMissing(doc[from])),
at(from, unset())
]
}
}
})

What happens when you run this, is that it will fetch all the documents of the type event and then export two patches for that document:

  • the at(to, setIfMissing(doc[from])) patch sets a new field called format with the value of the eventType , setIfMissing ensures that the value is set only if format doesn’t exist from before
  • at(from, unset()) removes the eventType value, and thus the field from the document

Save your changes. If you run npx sanity@latest migration list. You should get a table with the migration ID and title:

Run npx sanity@latest migration list and copy the content migration ID

Courses in the "Sanity developer essentials" track