
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeI can see from your error message that the response headers contain the exact information you need! The key headers are:
'retry-after': '1' - This tells you to wait 1 second before retrying'x-ratelimit-remaining-second': '0' - You've exhausted your current second's quotaSo the immediate answer is: wait 1 second (as indicated by the retry-after header) before making your next request.
However, for batch deletions, you're hitting rate limits because you're likely making too many individual requests. Here are much more efficient approaches:
1. Use transactions with multiple mutations (most efficient)
Instead of one mutation per request, batch multiple mutations into a single transaction. You can include many delete operations in one request:
const mutations = documents.map(doc => ({ delete: { id: doc._id } }));
// Batch them into chunks
const chunkSize = 100;
for (let i = 0; i < mutations.length; i += chunkSize) {
const chunk = mutations.slice(i, i + chunkSize);
await client.mutate(chunk);
// Add a small delay between batches if needed
await new Promise(resolve => setTimeout(resolve, 50));
}2. Use the Sanity CLI migration tool
The Sanity CLI migration tooling has built-in abstractions that automatically handle batching and rate limits. This is the recommended approach for bulk operations:
# For deleting all documents of a type
sanity documents delete '*[_type == "student"]'
# Or for a complete fresh start
sanity dataset delete <dataset-name>
sanity dataset create <dataset-name>The CLI migration tool provides automatic batching of mutations into transactions to avoid rate limits, which is exactly what you need for this scenario.
3. Implement retry logic with exponential backoff
When you do hit rate limits, implement a retry strategy that respects the retry-after header:
async function mutateWithRetry(mutations, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.mutate(mutations);
} catch (error) {
if (error.statusCode === 429) {
const retryAfter = parseInt(error.response.headers['retry-after'] || '1', 10);
console.log(`Rate limited. Waiting ${retryAfter}s before retry...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
} else {
throw error;
}
}
}
throw new Error('Max retries exceeded');
}By batching mutations properly (100+ deletes per request) instead of making individual mutation calls, you can delete thousands of documents efficiently without hitting rate limits. The key is reducing the number of HTTP requests by grouping multiple operations into single transactions.
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