# Migrating from Contentful to Contentstack in depth

- **Authors:** Tim Benniks
- **Published:** 2026-06-11
- **Updated:** 2026-06-11T12:48:23.383Z
- **Tags:** cli, automation, ai
- **Chapters:** 7
- **Source:** [https://developers.contentstack.com/guides/migrating-from-contentful-to-contentstack-in-depth](https://developers.contentstack.com/guides/migrating-from-contentful-to-contentstack-in-depth)

---

## Table of Contents

1. [Prerequisites and setup](#prerequisites-and-setup)
2. [The guided path: migrate with the AI skill](#the-guided-path-migrate-with-the-ai-skill)
3. [The expert path: migrate with CLI commands](#the-expert-path-migrate-with-cli-commands)
4. [Migrating your application code](#migrating-your-application-code)
5. [What migrates, what needs manual work, and how to verify](#what-migrates-what-needs-manual-work-and-how-to-verify)
6. [Troubleshooting and next steps](#troubleshooting-and-next-steps)
7. [Frequently asked questions](#frequently-asked-questions)

## What this guide is for

This guide is for developers moving a project from Contentful to Contentstack. It covers both the content migration (content types, entries, assets, locales, and more) and the application code that reads from the CMS.

There are two ways to run the migration, and this guide documents both. The guided path uses an AI skill that runs in an agentic chat window and orchestrates the migration for you. The expert path uses the Contentstack CLI plugin directly, one command at a time. Both paths run the same underlying tooling, so you can switch between them.

## How to use this guide

- If you want the fastest route, read chapters [The guided path: migrate with the AI skill](/guides/migrating-from-contentful-to-contentstack-in-depth/the-guided-path-migrate-with-the-ai-skill) and [The expert path: migrate with CLI commands](/guides/migrating-from-contentful-to-contentstack-in-depth/the-expert-path-migrate-with-cli-commands) and let the AI skill drive.


- If you want full control over each step, read chapters [The guided path: migrate with the AI skill](/guides/migrating-from-contentful-to-contentstack-in-depth/the-guided-path-migrate-with-the-ai-skill) and [Migrating your application code](/guides/migrating-from-contentful-to-contentstack-in-depth/migrating-your-application-code) for the CLI commands and flags.


- If you need to migrate application code, read chapter [What migrates, what needs manual work, and how to verify](/guides/migrating-from-contentful-to-contentstack-in-depth/what-migrates-what-needs-manual-work-and-how-to-verify).


- Before you treat the migration as done, read chapter [Troubleshooting and next steps](/guides/migrating-from-contentful-to-contentstack-in-depth/troubleshooting-and-next-steps) for the validation checklist and the known limitations.



## What this tool does and how it works

The migration is built from two pieces that work together: an AI skill and a Contentstack CLI plugin called @contentstack/cli-external-migrate. The skill handles orchestration and explanation. The plugin handles the actual data work.

One principle governs the whole design: the AI guides, the tooling executes. The AI never transforms your content. It reads your environment, decides which steps to run, executes trusted CLI commands, explains each decision, and validates the result. The export, conversion, and import all run through deterministic CLI tooling. This keeps the migration transparent and repeatable, which matters when you point it at a real space.

## What you'll learn

- How the AI skill and the CLI plugin divide responsibilities


- Which platform differences the migration handles for you


- What a full run produces on disk


- When to choose the guided path over the expert path



## The two paths

The guided path runs inside an agentic chat window. You describe what you want to migrate, and the skill checks prerequisites, runs the migration, shows progress, and produces a summary. It executes the same commands you would run by hand, so nothing is hidden.

The expert path runs the CLI commands yourself. You get the same export, conversion, audit, and import steps as discrete commands with flags you control. Use this path when you want to inspect intermediate output, script the migration, or run a subset of steps.

## How platform differences are handled

Contentful and Contentstack model some things differently, and the tooling translates between them:

- Contentful environments map to Contentstack branches (master maps to main).


- Contentful rich text converts to Contentstack JSON Rich Text Editor (RTE) format, with embedded entries and assets preserved as references.


- Contentful references resolve to Contentstack reference fields, which return arrays rather than single objects.


- Contentful roles map to built-in Contentstack roles where they match, and to custom roles where they do not.


- DAM marketplace app fields (Cloudinary, Bynder, Brandfolder, Frontify, Digizuite, Aprimo) map to the correct Contentstack asset shape.



## What a run produces

A full content run creates a fresh Contentstack stack in your organization and writes a set of artifacts to your workspace directory: the Contentful export JSON, a Contentstack import bundle, a mapper.json that records the field-UID mapping between source and target, a metadata.json with the new stack's credentials, and import logs. The code migration uses the mapper and metadata files, so keep the workspace directory until the whole migration is done.

## Key takeaways

- The AI skill orchestrates; the CLI plugin does the data work.


- The AI never transforms content directly, which keeps the migration safe and repeatable.


- The tooling translates platform differences such as environments, rich text, references, and roles.


- A run produces an export, a bundle, a field mapper, stack credentials, and logs.






---

## Prerequisites and setup

The migration runs from your machine and talks to both Contentful and Contentstack. Set up the prerequisites once before either path.

## What you'll learn

- Which tools and versions you need


- How to install the Contentstack CLI and the migration plugin


- How to authenticate against both platforms


- What inputs you need before you start



## Required tools

Confirm your environment before installing anything:

```bash
node --version    # must be 20 or higher
```

Node 20 or higher is required. If you run several Node versions through nvm or Homebrew, make sure the version on your PATH is 20 or higher, because a non-interactive shell sometimes resolves an older one.

## Install the CLI and plugin

Install the Contentstack CLI globally, then install the migration plugin:

```bash
npm install -g @contentstack/cli
csdx plugins:install @contentstack/cli-external-migrate
```

Verify the plugin is available:

```bash
csdx migrate --help
```

The output lists the migrate:create command. If it is missing, reinstall the plugin and check csdx plugins for a duplicate or stale migrate plugin.

## Set the destination region

Contentstack runs in several regions. Set the region that matches your destination stack before you log in:

```bash
csdx config:set:region AWS-EU
```

The supported region codes are AWS-NA, AWS-EU, AWS-AU, AZURE-NA, AZURE-EU, GCP-NA, and GCP-EU.

## Authenticate against both platforms

Log in to Contentstack with OAuth. The command opens your browser and detects when you finish:

```bash
csdx auth:login --oauth
```

Log in to Contentful with its CLI. This step is interactive and prompts you to open a browser and paste your management token:

```bash
npx contentful-cli login
```

Your Contentful management token is a secret. Do not paste it into files, commit it, or share it in chat. The migration reads it from the Contentful CLI's stored session.

## Gather your inputs

Before you start, have these ready:

- Your Contentful space ID, which you can list with npx contentful-cli space list.


- Your Contentstack organization UID, which is the org where the new stack will be created. if you use OAuth to log into Contentstack, we can derive the Org UID from your session.


- The local path to the application code you want to migrate, if you plan to migrate code.



## Key takeaways

- Node 20 or higher is required, and the version on your PATH must match.


- Install the CLI, then the @contentstack/cli-external-migrate plugin.


- Set the destination region before logging in.


- Authenticate against both Contentstack (OAuth) and Contentful (CLI login).


- Treat the Contentful management token as a secret.






---

## The guided path: migrate with the AI skill

The guided path runs the migration through an AI skill in an agentic chat window. It is the fastest route and the one most teams should start with. On a clean starter project, the full run finishes in under fifteen minutes.

## What you'll learn

- How to start a guided migration


- What the skill checks before it runs anything


- What each step produces and how progress is reported


- Where to find the artifacts when the run completes



## Start the migration

Open your agentic chat window with the migration skill installed, and state what you want:

```bash
I want to migrate my Contentful space to Contentstack.
```

The skill responds with the migration plan and begins by checking prerequisites. It confirms Node, the CLI, the plugin, your Contentstack login and region, and your Contentful login and accessible spaces. If anything is missing, it tells you exactly what to fix before continuing.

## How the run proceeds

The skill works through the migration in order and shows progress at each step. It gates the steps that touch live accounts or modify your code, so it asks before it creates a stack and before it edits your repository. The sequence is:

- Verify prerequisites and gather inputs such as the space ID and organization UID.


- Confirm the migrate plugin is installed and current.


- Run the content migration, which exports from Contentful, converts to a Contentstack bundle, creates a new stack, and imports the content.


- Migrate the application code that reads from the CMS.


- Show a completion summary with the new stack details and artifact locations.



After each step the skill surfaces the meaningful output, such as the exported entity counts and the new stack key, rather than a wall of logs.

## What the content step does

The content step runs a single command under the hood that chains export, conversion, and import. The skill captures the resulting stack name, stack API key, region, bundle path, and credentials file, and carries them into the code migration so you do not re-enter them.

## What the completion summary contains

When the run finishes, the skill reports the counts imported into the stack, the files it changed in your codebase, any field UIDs it had to guess, and any call sites it marked with a TODO(migration) comment for you to review. It also points you to the workspace directory holding the export, the bundle, the credentials, and the logs.

## Key takeaways

- Start the guided path by stating your migration intent in an agentic chat window.


- The skill checks every prerequisite before it runs anything.


- It gates stack creation and code edits behind explicit confirmation.


- It captures the new stack credentials and carries them into the code migration.


- The completion summary lists counts, changed files, guessed UIDs, and remaining TODOs.






---

## The expert path: migrate with CLI commands

The expert path gives you direct control over each migration step. Use it to inspect intermediate output, script the migration, or run a subset of the steps. The commands come from the same @contentstack/cli-external-migrate plugin the guided path uses.

## What you'll learn

- How to run the whole content migration in one command


- How to run the export, convert, audit, and import steps separately


- Which flags control each step


- How to check migration progress with a manifest



## Run the whole migration in one command

The migrate:create command exports the Contentful space, converts it to a Contentstack bundle, creates a new stack in your organization, and imports the content:

```bash
csdx migrate:create \  --source contentful \  --org <your-org-uid> \  --space-id <your-space-id> \  --download-assets \  --output ./migration-workspace \  --workspace ./migration-workspace
```

Useful flags:

- --source contentful declares the migration source. Contentful is the only supported source today.


- --org is the Contentstack organization UID where the new stack is created. If you omit it, the command prompts with a list.


- --space-id is the Contentful space to export.


- --download-assets includes asset binaries in the export.


- --include-drafts and --include-archived widen the export beyond published entries.


- --affix sets a content-type UID prefix (default CS).


- --output is the parent directory; the bundle is written to <output>/bundle (default ./output-dir).


- -y skips the import confirmation prompt (on by default; pass --no-yes to keep the prompt).



Provide your Contentful management token through the CONTENTFUL_MANAGEMENT_TOKEN environment variable, or pass it with --source-token. Prefer the environment variable so the token stays out of your shell history.

By default the command invites the Contentful space members into the new stack with their mapped roles, which sends invite emails. Pass --no-invite-users to skip the emails and only write the users-mapping.json report. To migrate every space a token can reach in one run, use --cf-org-id <contentful-org-id> instead of --space-id, which creates one stack per space.

## Run the steps separately

If you want to inspect or modify the bundle between steps, run the discrete commands instead. They share a workspace directory so the manifest can track progress across them. These subcommands do not appear in csdx migrate --help, which lists only migrate:create, but they ship with the plugin and run normally.

### Export from Contentful

Export the space to an export.json in your workspace:

```bash
csdx migrate:export \  --legacy contentful \  --space-id <your-space-id> \  --download-assets \  --output ./migration-workspace
```

The --include-drafts and --include-archived flags work here too. Prefer the CONTENTFUL_MANAGEMENT_TOKEN environment variable over passing the token as a flag.

### Convert to a Contentstack bundle

Convert the export into a Contentstack import bundle:

```bash
csdx migrate:convert \  --legacy contentful \  --input ./migration-workspace/export.json \  --output ./contentstack-import \  --master-locale en-us
```

The bundle is written to <output>/bundle and contains content types, entries, assets, references, and a mapper.json recording the field-UID mapping. Inspect the converted content types before importing:

```bash
ls ./contentstack-import/bundle/content_types/
cat ./contentstack-import/bundle/mapper.json
```

### Audit the bundle

The audit step wraps the existing Contentstack audit tooling to validate the bundle before import:

```bash
csdx migrate:audit \  --data-dir ./contentstack-import/bundle \  --report-path ./audit-reports
```

Review the report, and if the audit surfaces fixable issues, you can run csdx cm:stacks:audit:fix against the bundle before importing.

### Import into a stack

Import into an existing stack by API key:

```bash
csdx migrate:import \  --stack-api-key <your-stack-api-key> \  --data-dir ./contentstack-import/bundle \  -y
```

To create a new stack during import instead, pass --org <your-org-uid> rather than --stack-api-key, and optionally --stack-name to name it. The import target stack must be empty.

## Check progress

The migration writes a migration-manifest.json to the workspace. Check the status of each step at any time:

```bash
csdx migrate:status --workspace ./migration-workspace
```

## Key takeaways

- migrate:create runs export, convert, create stack, and import in one command.


- migrate:export, migrate:convert, migrate:audit, and migrate:import run the same steps discretely.


- The convert step produces a bundle and a mapper.json you can inspect before import.


- The import target stack must be empty, or let the command create a new one with --org.


- migrate:status reports progress from the workspace manifest.






---

## Migrating your application code

Once your content is in Contentstack, the next step is the code that reads from the CMS. The migration tool reads your repository, detects the framework and data-access approach, and rewrites the data layer in place.

## What you'll learn

- What the code migration changes and what it preserves


- Which inputs the code step needs from the content step


- How references and rich text differ after migration


- How the migration verifies itself



## What it changes and preserves

The code migration is mechanical and minimal. It detects your language, framework, and data-access approach, then migrates in the same shape: REST stays REST, GraphQL stays GraphQL, and Live Preview is reimplemented to match what was there. It preserves your function and component contracts and matches the surrounding code style rather than forcing a rewrite.

## Inputs from the content step

The code step needs two files the content step produced:

- mapper.json gives the Contentful-field-UID to Contentstack-field-UID mapping, so rewritten queries reference the correct field names.


- metadata.json supplies the new stack's Delivery SDK credentials: the stack API key, delivery token, environment, and a preview token if Live Preview is enabled.



Set the credentials in the migrated app's local .env file, which should be gitignored. Use the stack_api_key value for the API key, not stack_id.

## Reference and rich text differences

Two differences need attention after migration:

- Contentstack resolves references to arrays, not single objects. Every reference dereference becomes safe array access, such as entry.author?.[0]. Audit null safety wherever the old code assumed a single referenced object.


- Contentful rich text becomes Contentstack JSON RTE. Embedded entries and assets are preserved as references and rendered through the appropriate renderer.



## How verification works

The code migration runs a suite of post-migration checks covering Contentful residue, field access, SDK initialization, build, secrets, references, rich text, locales, assets, GraphQL, and Live Preview. A clean build is necessary but not sufficient, because a build cannot catch a wrong field UID or a reference-array bug. After the checks pass, smoke-test live queries against the real Contentstack stack before you treat the code as done.

When the migration is uncertain about a field UID or a behavior, it leaves a TODO(migration) comment at the call site rather than guessing silently. Review every one.

## Key takeaways

- The code migration preserves your framework, approach, and contracts.


- It needs mapper.json and metadata.json from the content step.


- Use stack_api_key for the API key and keep tokens in a gitignored .env.


- Convert reference access to safe array access and check null safety.


- A green build is not enough; smoke-test live queries and review every TODO.






---

## What migrates, what needs manual work, and how to verify

A real migration is more than content types and entries. This chapter lists what comes across automatically, what needs manual attention, and the checklist to confirm the migration is complete.

## What you'll learn

- The full set of content and configuration that migrates


- The items that require manual work after migration


- A verification checklist for content and code



## What migrates automatically

The content migration covers:

- Content types and fields, including help text, descriptions, default values, and slug handling


- Entries, including references, localized variants, and entry tags


- Assets and media, with re-linking


- Locales and languages, with master-locale detection and fallback


- Taxonomy and terms


- Rich text converted to JSON RTE, with embedded entries and assets preserved as references


- Environments mapped to branches


- Webhooks


- Roles and permissions, mapped to built-in or custom Contentstack roles


- Marketplace apps and extensions, including DAM apps such as Cloudinary and Bynder


- Delivery and preview token provisioning, with Live Preview and Personalize enabled



## What needs manual work

A few items cannot migrate cleanly, mostly because the source redacts or omits them:

- Webhook secret values are redacted in Contentful exports and cannot be read back. Re-enter them in Contentstack by hand.


- Publish rules require reconstruction through the Contentstack Management API, because they are not represented in Contentful exports.


- Users, memberships, and single sign-on configuration require re-invitation and setup.


- Releases and scheduled actions must be recreated and rescheduled.


- Global fields are an optional content-modeling refactor, not required for a one-to-one migration.



## Verification checklist

Confirm the content migration before moving on:

- Imported counts for locales, content types, assets, and entries match the exported counts.


- A sample entry resolves its references and renders its rich text.


- Localized entries and fallback behavior match the source.


- Assets carry the dimensions and types your components expect.



Then confirm the code migration:

- The app builds, and the migration check suite passes.


- The homepage and listing pages render published content from Contentstack.


- Reference-heavy and rich-text pages render correctly.


- Live Preview reads draft content where the app supports it.


- Every TODO(migration) comment has been reviewed.



## Key takeaways

- Most content and configuration migrates automatically, including environments, roles, and DAM apps.


- Webhook secrets, publish rules, users and SSO, and releases need manual work.


- Verify that imported counts match exported counts before trusting the migration.


- Confirm published delivery, references, rich text, and Live Preview in the migrated app.






---

## Troubleshooting and next steps

Most migration failures are recoverable. This chapter covers the common cases and where to go once the migration is stable.

## What you'll learn

- How to recover from the most common failures


- When to split content and code into separate passes


- What to do after the migration is complete



## Common failures

### The Contentstack token expired mid-run

A long import can outlast the OAuth token. The log shows a 401 about an invalid or expired token. Re-authenticate and re-run; the create command is safe to re-run because it creates a fresh stack each time:

```bash
csdx auth:login --oauth
```

### Contentful login is not recognized

If the migration cannot resolve your Contentful management token, run contentful login again, complete the browser flow, and retry. Verify access to the space with contentful space list.

### Node is too old

If a command fails with a Node version error, the shell resolved a Node below 20. Install and select Node 20 or higher with nvm install 22 && nvm use 22, then confirm with node --version before retrying.

### The import target stack is not empty

migrate:import requires an empty destination stack. Either point it at a fresh stack or let it create one with --org.

### Webhooks are missing after import

The importer processes webhooks in batches, and a known issue can skip webhooks after the first batch. Check the imported webhook count against the source and recreate any missing ones through the Contentstack Management API.

## When to split content and code

The automated code migration is strong on basic and mid-complexity sites. On a heavily customized architecture, run the content migration and the code migration as separate supervised passes rather than expecting one autonomous run to handle everything. Review the planned changes before applying them, and lean on the TODO(migration) comments.

## Next steps

After the migration is stable:

- Start the app with the new CS_* environment variables and confirm pages render against Contentstack.


- Invite your team, set up roles, and configure publishing workflows in the Contentstack dashboard.


- Set up webhooks and automation for deploys and publish events, and re-enter any webhook secrets.


- Review the Contentstack Delivery SDK, GraphQL, and Live Preview references for the patterns your app uses.



Support for additional source platforms such as Sanity, Storyblok, and Strapi is planned. The architecture adds a new source by implementing an export adapter and a conversion adapter, so the workflow in this guide stays the same as new sources arrive.

## Key takeaways

- Most failures are recoverable; re-running migrate:create is safe.


- Node below 20 and a non-empty destination stack are the most common blockers.


- Split content and code into separate passes for complex architectures.


- After migration, verify the live site, configure the dashboard, and re-enter webhook secrets.






---

## Frequently asked questions

### Does the AI transform my content during the migration?

No. The AI guides the migration and runs trusted CLI commands, but the export, conversion, and import all run through deterministic tooling. Your content is never passed through a model and regenerated, which keeps the migration transparent and repeatable.

### Can I run the migration without the AI skill?

Yes. The expert path uses the @contentstack/cli-external-migrate plugin directly. You can run the whole migration with migrate:create, or run migrate:export, migrate:convert, migrate:audit, and migrate:import as discrete steps. Both paths use the same tooling.

### What does the migration not handle automatically?

Webhook secret values, publish rules, users and single sign-on configuration, and releases and scheduled actions need manual work. Webhook secrets are redacted by Contentful and cannot be read back, so you re-enter them by hand. Global fields are an optional content-modeling enhancement, not required for a one-to-one migration.

### How long does a migration take?

On a clean starter project, the full content and code run finishes in under fifteen minutes. On a real space with several hundred entries and a DAM integration, the autonomous content run completes in roughly eight minutes. Code migration time depends on how complex your data layer is.

### Is Contentful the only supported source?

Today, yes. Contentful is the only supported source. The architecture was built to add new sources by implementing an export adapter and a conversion adapter, so Sanity, Storyblok, and Strapi are planned next.



---

## Frequently asked questions

### What are the two ways to run the migration from Contentful to Contentstack?

Use the guided path in an agentic chat window (AI skill orchestration) or the expert path by running @contentstack/cli-external-migrate commands directly.

### Does the AI skill transform or modify content during the migration?

No. The AI guides and orchestrates deterministic CLI commands; export, conversion, and import are executed by the CLI tooling for repeatable results.

### How are common platform differences handled during migration?

The tooling translates key differences, including environments to branches, rich text to Contentstack JSON RTE, references to reference fields, and role mappings.

### What files and artifacts does a full migration run produce?

It creates a new Contentstack stack and writes artifacts such as the Contentful export JSON, a Contentstack import bundle, mapper.json, metadata.json, and import logs.

### Why should you keep the workspace directory after the content migration completes?

The code migration relies on mapper.json and metadata.json to map fields and access the new stack, so the workspace is required until the full migration is done.

