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/cli

Export dataset

sanity dataset export production sanity-export.ndjson

This 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

SanityMeshBase
stringtext
textrichtext
block (Portable Text)richtext
numbernumber
datetimedatetime
booleanboolean
imagemedia
referencerelation

After Migration

🎊

Welcome to MeshBase!

No more GROQ queries to debug. Just simple REST API calls that work everywhere.