Does PlanetScale Work With Sanity?
PlanetScale and Sanity serve different purposes (database vs. headless CMS) and don't integrate directly, but they work well together in a complementary architecture.
Quick Facts
How PlanetScale Works With Sanity
PlanetScale and Sanity are designed to complement each other rather than replace one another. Sanity is a headless CMS for structured content management with real-time collaboration, while PlanetScale is a relational database for application data. In a typical architecture, you'd use Sanity for content (blog posts, page layouts, marketing copy) and PlanetScale for transactional data (user accounts, orders, analytics). Your backend API fetches content from Sanity's CDN and stores/queries relational data in PlanetScale. The integration requires writing a middleware layer—typically in Node.js, Python, or another backend language—that coordinates between both systems. Sanity provides webhooks to sync content changes to PlanetScale if needed, and the real-time collaboration features in Sanity don't conflict with PlanetScale's eventual consistency model since they handle different data types.
Best Use Cases
Syncing Sanity Content to PlanetScale via Webhook
npm install express mysql2 sanity-client dotenvimport express from 'express';
import mysql from 'mysql2/promise';
import crypto from 'crypto';
const app = express();
app.use(express.json());
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
waitForConnections: true,
connectionLimit: 5,
});
// Validate Sanity webhook signature
const verifySanityWebhook = (req, secret) => {
const signature = req.headers['sanity-hook-signature'];
const hash = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(req.body))
.digest('base64');
return signature === hash;
};
app.post('/webhooks/sanity', async (req, res) => {
if (!verifySanityWebhook(req, process.env.SANITY_WEBHOOK_SECRET)) {
return res.status(401).send('Unauthorized');
}
const { _id, _type, title, slug } = req.body.document;
const conn = await pool.getConnection();
try {
await conn.execute(
'INSERT INTO sanity_content (sanity_id, type, title, slug) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE title=?, slug=?',
[_id, _type, title, slug?.current, title, slug?.current]
);
res.json({ success: true });
} finally {
conn.release();
}
});
app.listen(3000, () => console.log('Webhook receiver running'));Known Issues & Gotchas
Data duplication complexity: Deciding what lives in Sanity vs. PlanetScale can create sync challenges
Fix: Establish a clear data ownership model upfront. Use Sanity webhooks to sync content changes to PlanetScale only when necessary. Keep Sanity as source-of-truth for content, PlanetScale for relational/transactional data.
No native connector means manual webhook management and custom sync logic
Fix: Build a lightweight webhook receiver endpoint that validates and syncs Sanity content changes to PlanetScale. Use tools like Zapier or Make for simple workflows, or custom serverless functions for complex logic.
PlanetScale's connection limits can impact high-concurrency scenarios when both APIs are hammering your database
Fix: Use connection pooling (PlanetScale Boost) and implement caching for frequently-accessed data. Consider separating read and write operations with replicas.
Alternatives
- •MongoDB + Sanity: Use MongoDB for flexible document storage alongside Sanity; better for unstructured data but loses relational integrity
- •Supabase + Sanity: PostgreSQL alternative with built-in auth and real-time subscriptions; more opinionated than PlanetScale but tighter integration ecosystem
- •Firebase + Sanity: Serverless real-time database with Sanity for content; simpler for small projects but less control over data schema and querying
Resources
Related Compatibility Guides
Explore more compatibility guides