Discussion on importing and publishing documents in Sanity, with some confusion around the "Publish" vs "Published" status.
Good news! When you import documents using the Sanity client, they're automatically published by default - you don't need to manually publish them in the Studio unless they have a drafts. prefix in their _id.
Published vs Draft Documents
When importing documents, the publish state depends on the _id:
- Without
drafts.prefix (e.g.,"_id": "abc-123") → Documents are published automatically - With
drafts.prefix (e.g.,"_id": "drafts.abc-123") → Documents remain as drafts
Publishing Imported Drafts Programmatically
If you did import documents as drafts (with the drafts. prefix), you can publish them programmatically without clicking through the Studio. Here are your options:
Option 1: Use createOrReplace (Recommended)
The simplest approach is to use createOrReplace to create published versions:
import {createClient} from '@sanity/client'
const client = createClient({
projectId: 'your-project-id',
dataset: 'your-dataset',
token: 'your-token',
apiVersion: '2024-01-01',
useCdn: false
})
// Publish a draft by creating/replacing the published version
const draftId = 'drafts.abc-123'
const publishedId = draftId.replace('drafts.', '')
const draftDoc = await client.getDocument(draftId)
await client.createOrReplace({
...draftDoc,
_id: publishedId
})
// Optionally delete the draft
await client.delete(draftId)Option 2: Import Without Draft Prefix (Easiest)
The easiest approach is to import documents without the drafts. prefix in the first place:
const documents = [
{
_id: 'post-123', // No 'drafts.' prefix
_type: 'post',
title: 'My Post',
// ... other fields
}
]
documents.forEach(doc => {
await client.createOrReplace(doc)
})UI Behavior Note
There's a UI quirk that can be confusing: even for published documents, the Studio shows a "Publish" button (greyed out) rather than "Published" when you navigate back to a document. This is just a UI state - the document is still published. You can verify by querying without the previewDrafts perspective or checking if the document appears in your frontend.
As one community member discovered: "Maybe they are 'published' even though they say 'Publish' in localhost:3333 and not 'Published'. Because I can see them in graphql deploys playground"
Bulk Publishing All Drafts
For bulk operations, you can create a migration script:
npx sanity@latest migration create publishDraftsThen implement the migration to publish all drafts:
import {defineMigration} from 'sanity/migrate'
export default defineMigration({
title: 'Publish all draft documents',
documentTypes: ['post'], // specify your types
filter: '_id in path("drafts.**")',
migrate: {
document(doc, context) {
// Create published version
const publishedId = doc._id.replace('drafts.', '')
return {
...doc,
_id: publishedId
}
}
}
})Key Takeaway
Imported documents are published by default unless you explicitly add the drafts. prefix to their IDs. No manual Studio work required! If you need to publish drafts programmatically, use createOrReplace with the non-draft ID, or better yet, import without the draft prefix from the start.
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.