ButterCMS also offers built-in migration options: the Migrations tool (Enterprise) for migrating content schemas, cloning environments, and moving content across sites or environments, and the Write API for programmatic content creation and updates.
Third-party migration tools
CMS2CMS
CMS2CMS offers automated migration between CMS platforms:- Automated content migration
- Supports many source platforms
- Handles media migration
- Preserves SEO settings
Custom migration scripts
For full control, build custom migration scripts:Node.js migration template
// migrate.js
const fs = require('fs');
require('dotenv').config();
const BUTTERCMS_API_URL = 'https://api.buttercms.com/v2';
const BUTTERCMS_WRITE_TOKEN = process.env.BUTTERCMS_WRITE_TOKEN;
class Migrator {
constructor() {
this.results = { success: [], errors: [] };
}
async createPage(pageData) {
const response = await fetch(`${BUTTERCMS_API_URL}/pages/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Token ${BUTTERCMS_WRITE_TOKEN}`
},
body: JSON.stringify(pageData)
});
if (response.ok) {
this.results.success.push(pageData.slug);
return await response.json();
} else {
const error = await response.text();
this.results.errors.push({ slug: pageData.slug, error });
return null;
}
}
async migrateFromFile(filePath) {
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
for (const page of data.pages) {
console.log(`Migrating: ${page.title}`);
await this.createPage(page);
await this.delay(200); // Rate limiting
}
return this.results;
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Usage
const migrator = new Migrator();
migrator.migrateFromFile('content.json')
.then(results => {
console.log('Success:', results.success.length);
console.log('Errors:', results.errors.length);
});
Python migration template
# migrate.py
import json
import time
import requests
from dotenv import load_dotenv
import os
load_dotenv()
BUTTERCMS_API_URL = 'https://api.buttercms.com/v2'
BUTTERCMS_WRITE_TOKEN = os.getenv('BUTTERCMS_WRITE_TOKEN')
class Migrator:
def __init__(self):
self.results = {'success': [], 'errors': []}
self.headers = {
'Authorization': f'Token {BUTTERCMS_WRITE_TOKEN}',
'Content-Type': 'application/json'
}
def create_page(self, page_data):
response = requests.post(
f'{BUTTERCMS_API_URL}/pages/',
json=page_data,
headers=self.headers
)
if response.status_code in [200, 201, 202]:
self.results['success'].append(page_data['slug'])
return response.json()
else:
self.results['errors'].append({
'slug': page_data['slug'],
'error': response.text
})
return None
def migrate_from_file(self, file_path):
with open(file_path, 'r') as f:
data = json.load(f)
for page in data.get('pages', []):
print(f"Migrating: {page.get('title')}")
self.create_page(page)
time.sleep(0.2) # Rate limiting
return self.results
# Usage
if __name__ == '__main__':
migrator = Migrator()
results = migrator.migrate_from_file('content.json')
print(f"Success: {len(results['success'])}")
print(f"Errors: {len(results['errors'])}")
Validation tools
JSON schema validation
const Ajv = require('ajv');
const ajv = new Ajv();
// Define schema for ButterCMS page
const pageSchema = {
type: 'object',
required: ['page_type', 'title', 'slug', 'fields'],
properties: {
page_type: { type: 'string', pattern: '^[a-z_]+$' },
title: { type: 'string', minLength: 1 },
slug: { type: 'string', pattern: '^[a-z0-9-]+$' },
status: { enum: ['draft', 'published'] },
fields: { type: 'object' }
}
};
const validate = ajv.compile(pageSchema);
// Validate before import
function validatePages(pages) {
const errors = [];
for (const page of pages) {
if (!validate(page)) {
errors.push({
page: page.title,
errors: validate.errors
});
}
}
return errors;
}
Content diff tool
// Compare source and migrated content
async function diffContent(sourcePages, butterPages) {
const differences = [];
for (const source of sourcePages) {
const butter = butterPages.find(p => p.slug === source.slug);
if (!butter) {
differences.push({
slug: source.slug,
issue: 'Missing in ButterCMS'
});
continue;
}
// Compare key fields
if (source.title !== butter.fields.title) {
differences.push({
slug: source.slug,
field: 'title',
source: source.title,
butter: butter.fields.title
});
}
// Add more field comparisons...
}
return differences;
}
Migration workflow automation
GitHub Actions
# .github/workflows/migrate.yml
name: Content Migration
on:
workflow_dispatch:
inputs:
source_file:
description: 'Source data file'
required: true
default: 'content.json'
jobs:
migrate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Run migration
env:
BUTTERCMS_WRITE_TOKEN: ${{ secrets.BUTTERCMS_WRITE_TOKEN }}
run: node migrate.js ${{ github.event.inputs.source_file }}
- name: Upload results
uses: actions/upload-artifact@v3
with:
name: migration-results
path: migration_results.json
ButterCMS support services
Assisted migration
ButterCMS offers assisted migration services:| Service | Availability | Contact |
|---|---|---|
| WordPress blog import | All plans | support@buttercms.com |
| Full site migration | Enterprise | support@buttercms.com |
| Custom migration support | Enterprise | support@buttercms.com |
| Write API enablement | On request | support@buttercms.com |
Getting help
- Documentation: docs.buttercms.com
- Support: support@buttercms.com
- Live Chat: Available in dashboard
- Knowledge Base: buttercms.com/kb