
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeYou can definitely patch documents from a client component! You don't need sanity/migrate for this - that's specifically for CLI-based content migrations. Here's what you need to know:
You can use @sanity/client to patch documents from any JavaScript environment, including React client components. Here's a basic example:
import {createClient} from '@sanity/client'
const client = createClient({
projectId: 'your-project-id',
dataset: 'your-dataset-name',
useCdn: false, // Important: set to false for mutations
apiVersion: '2025-02-06',
token: process.env.SANITY_API_TOKEN // Required for mutations
})
// Patch a document
async function updateDocument(documentId, newTitle) {
const result = await client
.patch(documentId)
.set({title: newTitle})
.commit()
return result
}The patch API supports various operations like set, unset, setIfMissing, insert, inc, and more.
⚠️ Never expose write tokens in client-side code! This is a critical security issue. If you put a token with write permissions directly in your browser code, anyone can inspect your code and use that token to modify or delete your content.
Instead of patching directly from a client component, create a server-side API endpoint that handles the mutation:
// app/api/update-document/route.js (Next.js App Router example)
import {createClient} from '@sanity/client'
const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
useCdn: false,
apiVersion: '2025-02-06',
token: process.env.SANITY_API_TOKEN // Safely stored server-side
})
export async function POST(request) {
const {documentId, updates} = await request.json()
// Add validation and authorization checks here!
const result = await client
.patch(documentId)
.set(updates)
.commit()
return Response.json(result)
}Then call this from your client component:
// Your client component
async function handleUpdate(documentId, newData) {
const response = await fetch('/api/update-document', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({documentId, updates: newData})
})
return response.json()
}If you're working within Sanity Studio (like in a custom input component), you don't use the client directly. Instead, you use the onChange callback with PatchEvent:
import {set, unset} from 'sanity'
function MyCustomInput(props) {
const {value, onChange} = props
const handleChange = (newValue) => {
onChange(newValue ? set(newValue) : unset())
}
return <input value={value} onChange={(e) => handleChange(e.target.value)} />
}@sanity/client with .patch() for programmatic updatesPatchEvent with set/unset when building Studio pluginssanity/migrate is for CLI-based content migrations, not runtime updatesThe key takeaway: while you can technically use the client in a browser component, you should always proxy mutations through a secure server-side endpoint to protect your API tokens.
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