Migrate from Sanity to MeshBase
Switch from Sanity's GROQ complexity to MeshBase's simple REST API. This guide covers exporting from Sanity and importing to MeshBase.
Why Leave Sanity?
πSimpler API
GROQ has a steep learning curve. MeshBase uses standard RESTβfamiliar to every developer.
π°Better Pricing
Sanity charges for API requests and bandwidth. MeshBase has predictable, simple pricing.
π¨Easier Content Studio
No need to build custom React components. MeshBase provides a complete UI out of the box.
β‘Faster Development
Less time learning GROQ, more time building features.
Export from Sanity
Install Sanity CLI
npm install -g @sanity/cliExport dataset
sanity dataset export production sanity-export.ndjsonThis creates an NDJSON file with all your documents.
Transform Sanity Data
// transform-sanity.js
const fs = require('fs');
const readline = require('readline');
async function transformSanity() {
const meshbaseData = {};
const fileStream = fs.createReadStream('sanity-export.ndjson');
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
const doc = JSON.parse(line);
// Skip system documents
if (doc._id.startsWith('_')) continue;
const contentType = doc._type;
if (!meshbaseData[contentType]) {
meshbaseData[contentType] = [];
}
// Transform Sanity document to MeshBase entry
const entry = {
...doc,
// Remove Sanity-specific fields
_id: undefined,
_type: undefined,
_createdAt: undefined,
_updatedAt: undefined,
_rev: undefined,
// Handle portable text
...transformPortableText(doc),
// Handle references
...transformReferences(doc)
};
meshbaseData[contentType].push(entry);
}
fs.writeFileSync(
'meshbase-import.json',
JSON.stringify(meshbaseData, null, 2)
);
console.log('β
Sanity data transformed!');
}
function transformPortableText(doc) {
const result = {};
for (const [key, value] of Object.entries(doc)) {
if (Array.isArray(value) && value[0]?._type === 'block') {
// Convert Portable Text to HTML or markdown
result[key] = portableTextToHtml(value);
}
}
return result;
}
function portableTextToHtml(blocks) {
return blocks.map(block => {
if (block._type === 'block') {
const text = block.children.map(c => c.text).join('');
return `<p>${text}</p>`;
}
return '';
}).join('');
}
function transformReferences(doc) {
const result = {};
for (const [key, value] of Object.entries(doc)) {
if (value?._ref) {
// Sanity reference - store the ID
result[key] = value._ref;
}
}
return result;
}
transformSanity();Import to MeshBase
// import-to-meshbase.js
const data = require('./meshbase-import.json');
const API_URL = 'https://api.meshbase.io/v1';
const API_KEY = 'your-admin-key';
async function importToMeshBase() {
for (const [contentType, entries] of Object.entries(data)) {
console.log(`Importing ${entries.length} ${contentType}...`);
for (const entry of entries) {
await fetch(`${API_URL}/${contentType}`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(entry)
});
}
}
console.log('β
Import complete!');
}
importToMeshBase();Field Type Mapping
| Sanity | MeshBase |
|---|---|
string | text |
text | richtext |
block (Portable Text) | richtext |
number | number |
datetime | datetime |
boolean | boolean |
image | media |
reference | relation |
After Migration
π
Welcome to MeshBase!
No more GROQ queries to debug. Just simple REST API calls that work everywhere.