> ## Documentation Index
> Fetch the complete documentation index at: https://buttercms.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Contentful to ButterCMS migration

> Migrate from Contentful to ButterCMS — covers content type mapping, field conversion, rich text, references, and a complete migration script template.

## Why migrate from Contentful?

### Common reasons for migration

| Contentful Challenge            | ButterCMS Solution                           |
| ------------------------------- | -------------------------------------------- |
| **Complex content modeling**    | Intuitive visual content type builder        |
| **Steep learning curve**        | User-friendly interface for marketers        |
| **Difficult bulk data imports** | Write API for programmatic imports           |
| **Pricing scales with content** | Predictable pricing with generous limits     |
| **Developer-heavy workflows**   | Balance between developer and marketer needs |
| **Complex API structure**       | Simple, intuitive REST API                   |

### Feature comparison

| Feature              | Contentful                               | ButterCMS                                    |
| -------------------- | ---------------------------------------- | -------------------------------------------- |
| **Content Modeling** | Content Types with complex relationships | Page Types, Collections, Components          |
| **Blog Engine**      | Must build from scratch                  | Built-in blog with categories, tags, authors |
| **Preview**          | Requires setup                           | Built-in preview functionality               |
| **Localization**     | Available                                | Available with visual locale switcher        |
| **Components**       | Embedded entries                         | Visual Component Library                     |
| **Migrations**       | CLI-based migrations                     | Visual migration tool (Enterprise)           |
| **Media**            | Asset management                         | CDN-hosted Media Library                     |
| **API**              | GraphQL + REST                           | REST API                                     |

## Migration planning

### Step 1: Audit your Contentful content

Before migrating, create an inventory of your Contentful content:

**Content Types to identify:**

* Entry types (equivalent to ButterCMS Page Types)
* Assets (equivalent to ButterCMS Media)
* Content entries (equivalent to Pages or Collection Items)
* Locales configured
* Webhooks set up
* API integrations

### Contentful to ButterCMS mapping

| Contentful Concept | ButterCMS Equivalent    | Notes                              |
| ------------------ | ----------------------- | ---------------------------------- |
| Content Type       | Page Type               | Define schema for pages            |
| Entry              | Page or Collection Item | Depends on use case                |
| Asset              | Media Library item      | Automatic CDN hosting              |
| Space              | Site                    | One space = one ButterCMS site     |
| Environment        | Environment             | Staging/Production environments    |
| Locale             | Locale                  | Similar localization approach      |
| Embedded Entry     | Component or Reference  | Use Components for reusable blocks |
| Rich Text          | WYSIWYG                 | Similar functionality              |
| Reference          | Reference field         | One-to-One or One-to-Many          |
| Array              | Repeater                | For lists of items                 |
| Link               | Reference               | For content relationships          |

### Step 2: Map content types to ButterCMS

**Contentful Content Types** become **ButterCMS Page Types** or **Collections**:

<AccordionGroup>
  <Accordion title="When to use Page Types">
    * Content that represents a webpage
    * Content with SEO requirements
    * Content that needs scheduling
    * Content with complex field structures
    * Examples: Landing pages, product pages, case studies
  </Accordion>

  <Accordion title="When to use Collections">
    * Reference data used across pages
    * Lists of items without individual URLs
    * Reusable structured data
    * Examples: Categories, authors, testimonials, FAQs
  </Accordion>

  <Accordion title="When to use Blog Engine">
    * Standard blog posts with author, categories, tags
    * Content that follows a blog publishing workflow
    * SEO-optimized article content
  </Accordion>
</AccordionGroup>

### Step 3: Map field types

| Contentful Field Type | ButterCMS Field Type     | Migration Notes                              |
| --------------------- | ------------------------ | -------------------------------------------- |
| Short text            | Short Text               | Direct mapping                               |
| Long text             | Long Text or WYSIWYG     | Choose based on formatting needs             |
| Rich text             | WYSIWYG                  | Rich text content preserved                  |
| Number (Integer)      | Number                   | Direct mapping                               |
| Number (Decimal)      | Number                   | Direct mapping                               |
| Date/Time             | Date                     | Date fields supported                        |
| Location              | Short Text (coordinates) | Store as formatted string or separate fields |
| Boolean               | Checkbox                 | Direct mapping                               |
| JSON                  | Long Text                | Store as JSON string                         |
| Media (Image)         | Media                    | Upload to ButterCMS CDN                      |
| Media (File)          | Media                    | Upload to ButterCMS CDN                      |
| Reference (One)       | Reference (One-to-One)   | Link to Page Type or Collection              |
| Reference (Many)      | Reference (One-to-Many)  | Link to multiple items                       |
| Array                 | Repeater                 | For repeating sets of fields                 |

## Migration process

### Step 1: Export content from Contentful

Use the Contentful Export tool to export your content:

```bash theme={null}
# Install Contentful CLI
npm install -g contentful-cli

# Login to Contentful
contentful login

# Export space content
contentful space export --space-id YOUR_SPACE_ID --export-dir ./export
```

This creates JSON files containing:

* Content types
* Entries
* Assets
* Locales

### Step 2: Create ButterCMS content structure

Before importing content, set up your ButterCMS content types:

1. **Create Page Types** matching your Contentful content types
2. **Create Collections** for reference data
3. **Create Components** for reusable content blocks
4. **Configure Locales** matching your Contentful setup

### Step 3: Transform and import content

Use the ButterCMS Write API to import transformed content:

```javascript theme={null}
// Example: Transform Contentful entry to ButterCMS page
function transformContentfulEntry(entry, contentType) {
  const fields = entry.fields;
  const locale = 'en-US'; // or iterate through locales

  return {
    "page-type": contentType.toLowerCase().replace(/ /g, '_'),
    status: entry.sys.publishedAt ? "published" : "draft",
    title: fields.title?.[locale] || fields.name?.[locale],
    slug: fields.slug?.[locale] || generateSlug(fields.title?.[locale]),
    fields: {
      // Map each field from Contentful to ButterCMS schema
      title: fields.title?.[locale],
      body: fields.content?.[locale],
      summary: fields.excerpt?.[locale] || '',
      featured_image: fields.featuredImage?.[locale]?.fields?.file?.url,
      publish_date: entry.sys.publishedAt || new Date().toISOString()
    }
  };
}

// Import to ButterCMS
async function importToButterCMS(butterPage) {
  const response = await fetch('https://api.buttercms.com/v2/pages/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Token ${BUTTERCMS_WRITE_TOKEN}`
    },
    body: JSON.stringify(butterPage)
  });

  return response.json();
}
```

### Step 4: Handle assets/media

Contentful assets need to be uploaded to ButterCMS:

```javascript theme={null}
// Download Contentful asset and prepare for ButterCMS
async function migrateAsset(contentfulAsset) {
  const assetUrl = `https:${contentfulAsset.fields.file['en-US'].url}`;

  // Option 1: Use the URL directly (ButterCMS can fetch external images)
  // Option 2: Download and upload to ButterCMS Media Library

  // For direct URL usage in content:
  return assetUrl;
}
```

<Tip>
  ButterCMS supports external image URLs in content fields. For optimal performance and CDN delivery, upload assets to the ButterCMS Media Library.
</Tip>

### Step 5: Handle references and relationships

Contentful references need special handling:

```javascript theme={null}
// For Collection references (e.g., categories)
async function createCollectionItemAndGetID(contentfulEntry, collectionKey) {
  // First, create the collection item
  const response = await fetch('https://api.buttercms.com/v2/content/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Token ${BUTTERCMS_WRITE_TOKEN}`
    },
    body: JSON.stringify({
      key: collectionKey,
      status: 'published',
      fields: [
        {
          en: {
            name: contentfulEntry.fields.name['en-US'],
            slug: contentfulEntry.fields.slug['en-US']
          }
        }
      ]
    })
  });

  const result = await response.json();
  return result.data.meta.id; // Use this ID for references
}
```

### Step 6: Handle rich text content

Contentful rich text needs transformation to HTML for ButterCMS WYSIWYG:

```javascript theme={null}
import { documentToHtmlString } from '@contentful/rich-text-html-renderer';

function transformRichText(richTextField) {
  // Convert Contentful rich text to HTML
  return documentToHtmlString(richTextField);
}
```

## Handling specific Contentful features

### Embedded entries (Components)

Contentful embedded entries map to ButterCMS Components:

1. Create a Component in ButterCMS matching the embedded entry structure
2. When migrating, extract embedded entries from rich text
3. Use Component Picker fields to allow dynamic component addition

### Localization

ButterCMS provides field-level localization. Set up locales in Settings, then provide locale-specific content in API requests using locale keys in the fields object:

1. Set up matching locales in ButterCMS Settings
2. During migration, iterate through each locale
3. Use locale keys in the fields object when creating content via Write API

```javascript theme={null}
// Create localized content
const localizedPage = {
  "page-type": "article",
  status: "published",
  title: "My Article",
  slug: "my-article",
  fields: {
    en: {
      title: "English Title",
      body: "English content..."
    },
    de: {
      title: "German Title",
      body: "German content..."
    }
  }
};
```

### Webhooks

Re-create your webhook integrations in ButterCMS:

1. Go to **Settings → Webhooks**
2. Add webhook endpoints
3. Select events to trigger webhooks
4. Update any receiving applications with new payload format

## Migration script template

```javascript theme={null}
// migration.js - Contentful to ButterCMS migration script
const contentful = require('contentful-management');
const fetch = require('node-fetch');

const CONTENTFUL_SPACE_ID = process.env.CONTENTFUL_SPACE_ID;
const CONTENTFUL_ACCESS_TOKEN = process.env.CONTENTFUL_ACCESS_TOKEN;
const BUTTERCMS_WRITE_TOKEN = process.env.BUTTERCMS_WRITE_TOKEN;

async function migrate() {
  // 1. Connect to Contentful
  const client = contentful.createClient({
    accessToken: CONTENTFUL_ACCESS_TOKEN
  });

  const space = await client.getSpace(CONTENTFUL_SPACE_ID);
  const environment = await space.getEnvironment('master');

  // 2. Get all content types
  const contentTypes = await environment.getContentTypes();
  console.log(`Found ${contentTypes.items.length} content types`);

  // 3. Migrate each content type
  for (const contentType of contentTypes.items) {
    console.log(`Migrating: ${contentType.name}`);

    // Get entries for this content type
    const entries = await environment.getEntries({
      content_type: contentType.sys.id
    });

    // Transform and import each entry
    for (const entry of entries.items) {
      const butterPage = transformEntry(entry, contentType);
      await importToButterCMS(butterPage);
    }
  }

  console.log('Migration complete!');
}

function transformEntry(entry, contentType) {
  // Implement your field mapping logic here
  // Return ButterCMS-compatible object
}

async function importToButterCMS(page) {
  // Implement Write API call
}

migrate().catch(console.error);
```

## Post-migration checklist

* [ ] All content types created in ButterCMS
* [ ] All entries migrated successfully
* [ ] Media assets uploaded and references updated
* [ ] Localized content available in all locales
* [ ] Reference relationships working correctly
* [ ] Webhooks reconfigured
* [ ] Frontend application updated with new API calls
* [ ] Preview functionality tested
* [ ] Publishing workflow tested
* [ ] Team members trained on new interface

## Differences to note

| Aspect               | Contentful                   | ButterCMS               |
| -------------------- | ---------------------------- | ----------------------- |
| **API Style**        | GraphQL + REST               | REST only               |
| **Content Delivery** | CDN via Content Delivery API | Global CDN built-in     |
| **Rate Limits**      | Per-second limits            | Monthly API call limits |
| **Preview**          | Preview API                  | Built-in preview        |
| **Environments**     | Multiple environments        | Staging + Production    |
| **CLI**              | Full CLI tooling             | API-first approach      |
