What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
Migrating to Agility
Export a Contentful space with the Contentful CLI or the Content Delivery API, then map content types, entries, assets, references, rich text and localized fields to Agility models, linked content and locales.
Last verified: 2026-10-03 against Contentful's official tooling documentation: the Contentful CLI
space exportcommand, thecontentful-export,contentful-migrationandcontentful.jslibraries, and therich-textpackages. Check the current Contentful documentation for your account before relying on a detail here.
This guide applies the phases in Migrating to Agility to a Contentful space. It covers the export options Contentful provides, how its content model maps to Agility, and the parts that need care: references, rich text and localized fields.
| Option | What you get | Notes |
|---|---|---|
Contentful CLI: contentful space export | One JSON file with contentTypes, entries, assets, locales, webhooks and editorInterfaces | Uses a management token. One environment per export (--environment-id, default master). |
The contentful-export library | The same export, from your own script | Pass a deliveryToken to export the latest published versions through the Content Delivery API instead. |
Content Delivery API, for example through contentful.js | Entries and assets as your published site sees them | Can return all locales at once and resolve linked entries. |
| Sync API | An initial full sync, then only what changed, using nextSyncToken | Useful for the final sync at cutover. |
Options on space export worth knowing:
--include-drafts and --include-archived are off by default, so drafts and archived entries are left out unless you ask for them.--download-assets downloads the asset files as well as their metadata. You need the files to upload them to Agility.--skip-content-model or --content-only export only entries and assets, for repeat runs once the model is settled.--query-entries limits the export to matching entries, for example content_type=blogPost.--max-allowed-limit sets how many items are requested per page (default 1000). Lower it if responses are too large.Published or latest? Exporting through the Management API gives you the latest version of each entry, including changes that were never published. Exporting with a delivery token gives you what is published. Decide which one you are migrating, and tell content owners.
contentful space export \
--space-id <space-id> \
--environment-id master \
--management-token <token> \
--download-assets \
--export-dir ./contentful-export
| Contentful | Agility | Notes |
|---|---|---|
| Content type | Content model plus a container (list) | A content type used as a page building block may be better as a component model. |
| Entry | Content item | Store the entry's sys.id in a SourceID Text field so re-runs update instead of duplicating. |
| Asset | A file in the Agility media library | Referenced from Image, File, Gallery or List of Files fields. |
| Locale | Agility locale | Map codes explicitly, for example Contentful en-US to Agility en-us. |
| Environment | Export one environment, usually master |
| Contentful field type | Agility field type |
|---|---|
Symbol (short text) | Text |
Text (long text) | Multi-Line Text, or a Markdown field if the content is Markdown |
RichText | HTML (see Rich text below) |
Integer | Number |
Number | Decimal |
Date | Date/Time |
Boolean | True/False |
Location | Two Decimal fields (latitude and longitude), or a Text field |
Object (JSON) | Multi-Line Text holding the JSON, or a custom field |
Link to an asset | Image or File |
Link to an entry | Linked Content (a dropdown for a single item) |
Array of Symbol | Drop-down List if the values come from a fixed set, otherwise linked content to a small list |
Array of Link to entries | Linked Content (a search list box, or a nested list) |
Array of Link to assets | Gallery, or List of Files |
ResourceLink | Linked Content, after importing the linked resource |
Field settings carry over too: a required field should be required in Agility, and an in validation (a fixed set of allowed values) becomes the choices of a Drop-down List. See Fields and Linked Content Field Types.
In the export, a reference is a link object, not the linked content itself:
"author": { "en-US": { "sys": { "type": "Link", "linkType": "Entry", "id": "5KsDBWseXY6QegucYAoacS" } } }
Import in dependency order, keeping a map from Contentful sys.id to the Agility content ID (or, for assets, the uploaded cdn.aglty.io URL):
If entries reference each other in a cycle, import them in two passes: first save the items with their linked fields empty, then save again with the links filled in. In Agility, a linked-content dropdown stores the linked item's content ID in its _ValueField companion and the display text in its _TextField.
Contentful stores rich text as a JSON document, not HTML. Contentful's own @contentful/rich-text-html-renderer package converts a rich text document to HTML, which you can save to an Agility HTML field. Before you convert:
@contentful/rich-text-links to list the entries and assets a document links to, so you can import them first.Each Contentful field is either localized or not (localized: true or false). In an export that includes all locales, every field value is keyed by locale code:
"fields": {
"title": { "en-US": "Hello", "fr-CA": "Bonjour" },
"slug": { "en-US": "hello" }
}
In Agility, the same content item has the same content ID in every locale. Create the item in your main locale, then save the same content ID in each other locale to create its locale variants. See Creating Content and Pages in Other Locales. For a field that isn't localized in Contentful, write the same value into each locale variant.
Use the Management SDK and the approach in Migrating Content into Agility with an AI Agent: look up existing items by SourceID, upload assets, save in sequential batches and check every result. For a reviewable first pass, an AI agent with the Agility MCP Server can read a sample of the export, propose models and import 10 to 20 entries into Staging.
// One Contentful entry (exported with all locales) to one Agility item per locale.
function toAgilityItems(entry: any, existing: Map<string, number>, localeMap: Record<string, string>) {
return Object.entries(localeMap).map(([cfLocale, agilityLocale]) => ({
locale: agilityLocale,
item: {
contentID: existing.get(entry.sys.id) ?? -1,
properties: {definitionName: "BlogPost", referenceName: "BlogPosts"},
fields: {
Title: entry.fields.title?.[cfLocale] ?? entry.fields.title?.["en-US"],
Slug: entry.fields.slug?.[cfLocale] ?? entry.fields.slug?.["en-US"],
SourceID: entry.sys.id,
},
},
}))
}
Save the main locale first so each item gets its content ID, record that ID, then save the other locales with the same content ID. Throughput guidance is in Migrating to Agility.
The URLs of a Contentful-powered site are built by its front end, often from a slug field. In Agility you can rebuild that routing with pages in the sitemap and with dynamic pages, which generate one page per item in a list from a path formula such as the slug. See Generating Dynamic Pages From Content.
List the current site's URLs from its sitemap or a crawl, compare them with the new paths, and add a 301 redirect in Agility's URL Redirections for every URL that changes. See Keep Your Search Rankings Through a Migration.
At cutover, use the Sync API's nextSyncToken from your last full run to fetch only what changed during the content freeze. See the Migration Cutover Runbook.