Patching documents in Sanity client components
You 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:
Using the Sanity Client to Patch Documents
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.
Important Security Consideration
⚠️ 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.
The Safe Approach: Use Server-Side API Routes
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 Building a Studio Plugin
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)} />
}Summary
- ✅ Use
@sanity/clientwith.patch()for programmatic updates - ❌ Never expose write tokens in client-side code
- ✅ Create server-side API routes to safely handle mutations
- ✅ Use
PatchEventwithset/unsetwhen building Studio plugins - ℹ️
sanity/migrateis for CLI-based content migrations, not runtime updates
The 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.
Show original thread6 replies
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.