How to change the _type of a document in Sanity.io using the terminal or Postman.

48 replies
Last updated: Feb 10, 2021
Is there a way to change
_type
of a document? I changed
name
in the schema but it didn't change in the old documents and now I can't access them. I tried exporting, changing the
_type
manually and importing the new dataset but I get this error
The mutation(s) failed: Cannot modify immutable attribute "_type"
AI Update

Unfortunately, you've discovered one of the fundamental constraints of Sanity's Content Lake: the _type attribute is immutable and cannot be changed after a document is created. This is by design to maintain data integrity and consistent relationships between documents and their schemas.

When you renamed the document type in your schema, it created a mismatch - the old documents still have the original _type value, but your schema no longer recognizes that type, which is why you can't access them in Studio.

The Solution: Create New Documents

Since you can't modify _type directly (even through export/import), you need to create entirely new documents with the new type. Here's how to approach this:

The Sanity CLI migration tool is built for exactly this scenario:

npx sanity@latest migration create changeDocumentType

Then write a migration script that:

  1. Queries documents with the old _type
  2. Creates new documents with the new _type and copies all the content
  3. Optionally deletes the old documents
import {defineMigration, at, setIfMissing} from 'sanity/migrate'

export default defineMigration({
  title: 'Change document type from oldType to newType',
  
  migrate: {
    async document(doc, context) {
      if (doc._type === 'oldType') {
        // Create new document with new type
        const newDoc = {
          ...doc,
          _type: 'newType',
          _id: doc._id.replace('drafts.', ''), // or generate new ID
        }
        
        await context.client.create(newDoc)
        
        // Delete old document
        await context.client.delete(doc._id)
      }
    }
  }
})

Option 2: Manual Script with Sanity Client

You can also write a custom script using the Sanity client:

import {createClient} from '@sanity/client'

const client = createClient({
  projectId: 'your-project-id',
  dataset: 'your-dataset',
  token: 'your-token',
  apiVersion: '2024-01-01',
  useCdn: false
})

const oldDocs = await client.fetch(`*[_type == "oldType"]`)

for (const doc of oldDocs) {
  const {_id, _rev, _updatedAt, _createdAt, ...content} = doc
  
  // Create new document with new type
  await client.create({
    ...content,
    _type: 'newType',
    _id: _id, // Keep same ID or generate new one
  })
  
  // Delete old document
  await client.delete(_id)
}

Important Considerations

  1. Document IDs: You can keep the same _id values if you delete the old documents first, or generate new IDs if you want to keep both temporarily
  2. References: If other documents reference these documents, those references will still work if you keep the same _id
  3. Drafts: Remember to handle both published documents and drafts (which have IDs prefixed with drafts.)
  4. Test first: Always test your migration on a development dataset before running on production

Temporary Workaround

While you're preparing your migration, you can temporarily add the old type back to your schema (just the basic structure) so you can access those documents in Studio. This gives you time to plan and execute the migration properly.

The key takeaway: changing _type requires creating new documents, not modifying existing ones. It's a full data migration rather than a simple update, but the CLI migration tool makes this process much more manageable.

When I’ve needed to change the _type, I’ve used
sanity dataset export
to pull the data, edited the .ndjson file, then used
sanity dataset import
to put everything back.
Tried it already but it says that "_type" is immutable
Sorry, I left out the important part. With the
--replace
flag.
This is what I get
Sorry, let me double-check what I did. I know I faced the same situation.
I could just change the id and import them and it would probably work but that would leave the old documents in the dataset.
Shoot. Sorry about this, Neycho. Yes, I definitely did what you just suggested—copied the documents of the old _type to new ones and then uploaded that. I suppose you could do that and then use the HTTP API to query the old `_type`s and delete them.
I’m going to try that now and will let you know how it goes.
This seems unnecessarily complex 😄 . Thank you for taking your time helping me.
My pleasure! Do you already have a write token? If not, and you want to do this too, you’ll need to set one at manage.sanity.io .
Just created one.
Okay, great. Do you use Postman or are you comfortable doing this in the terminal?
Well, neither but I will try with the terminal
k
Have you already uploaded your data with the new _types?
Yes
Okay. What is the old _type you want to delete?
product
and
category
Okay, let’s do them one at a time.
And your dataset is production?
what do you mean by that? It's still in development
or do you mean its called production
Correct. The latter. Sorry.
It's called
biovitalis
Okay.
You’ll want to replace XXXXXXXX with your projectId and AUTH_TOKEN with your auth token you just created. Notice there’s a single quotation mark right after it.

curl --location --request POST '<https://XXXXXXXX.api.sanity.io/v1/data/mutate/biovitalis>' \
--header 'Authorization: Bearer AUTH_TOKEN' \
--header 'Content-Type: application/json' \
--data-raw '{
  "mutations": [
    {
      "delete": {
        "query": "*[_type == '\''product'\'']"
      }
    }
  ]
}
'
Paste this in your terminal and press enter. You’ll get confirmation or an error.
error
Multiple
Missing expression after unary operator '--'.
Hmmm… Okay, let’s try this:

curl --location --request POST '<https://XXXXXXXX.api.sanity.io/v1/data/mutate/test>' --header 'Authorization: <TOKEN>' --header 'Content-Type: application/json' --data-raw '{"mutations": [{"delete": {"query": "*[_type == '\''product'\'']"}}]}'
Same thing. Your token for &lt;TOKEN&gt;, your projectId for XXXXXXXX.
well, now I get this
oh, wait it says "test" not "biovitalis"
same error even after I changed it
should I just install Postman
I think you can replace
--location --request
with
-X
.
-X is --request and I don’t think --location is necessary.
You have a biovitalis dataset, but it’s empty.
If you go to https://manage.sanity.io/projects/ , select your project, then select Datasets, what do you see?
It should have 7 documents in it
Hmmm…
But hey I don't want to take more of your time than I already did. So I could probably handle this myself with some digging in the docs.
I don’t mind at all. Please do follow up if you get stuck.
(More than I’ve already gotten you stuck. 🥺)
Sure, thank you again. You are the MVP 🙌
Well, any progress is progress.
I was able to delete the documents. I downloaded Postman and it was pretty easy with it.
Happy to hear it! 😀

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?