← All playbooks
CMS migration

Drupal → Contentful

Read Drupal content through JSON:API, reshape it for a Contentful content model, and load it with the Content Management API or the CLI. Contentful's own migration article says referenced entries have to exist first, and HTML has to become rich text.

Typical timeline15 to 40 business days50 to 120 hours active work
Statusneeds review
Source profileDrupal JSON:API documentation reviewed 2026-11-05
Destination profileContentful import and export documentation reviewed 2026-11-05
Documentation date
Review window
Evidence4 sources
This route needs review.Use it as a planning baseline, then verify the dated sources and test with representative data before production.
Before you migrate

Should you make this move?

Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.

Current platform

Drupal

Reasons to stay
  • Content types, fields, and a deep module ecosystem fit complex publishing sites
  • Editors get a purpose-built publishing workflow instead of raw files
Reasons to leave
  • Views, custom fields, and module data need an explicit map before they mean anything in another CMS
  • Themes, extensions, and content models add maintenance and portability constraints
New platform

Contentful

What gets better
  • Mature structured content APIs, localization, roles, and ecosystem support enterprise publishing
  • Editors get a purpose-built publishing workflow instead of raw files
What gets worse
  • Content-model complexity, API usage, and pricing can create significant platform dependence
  • Themes, extensions, and content models add maintenance and portability constraints
Best of the move

Contentful: Mature structured content APIs, localization, roles, and ecosystem support enterprise publishing. This removes a major source-side concern: Views, custom fields, and module data need an explicit map before they mean anything in another CMS.

Worst of the move

What you lose: Content types, fields, and a deep module ecosystem fit complex publishing sites. What you inherit: Content-model complexity, API usage, and pricing can create significant platform dependence.

Jump to a section
01At a glance

Know the shape of the move.

Transfer outcome10 features audited
Transfer outcome distributionClean transfer: 0, Partial transfer: 5, Manual rebuild: 5, Not transferred: 0.
Clean0
Partial5
Manual5
Lost0
Mapping route8 of 9 fields have a destination path

This timeline assumes

  • JSON:API is enabled on a Drupal environment you are allowed to read. The module page is the core HTTP API for entities.
  • You have a Contentful space and a management token stored outside the repo.
  • The content model is already created. Contentful's article says the import follows the model, it does not invent one from Drupal fields.
  • You will transform HTML with Contentful's HTML-to-rich-text library, which their article says they maintain.
  • Drupal stays up until assets in Contentful match the files you listed.
02What transfers

What survives the move.

“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.

ItemOutcomeImpactWhat happensMitigation
Content modelmanualcriticalContentful entries follow content types you define. Drupal content types and fields do not become those types by exporting JSON.Design the types first. Write a map from each Drupal field to a Contentful field.
EntitiespartialcriticalJSON:API can read entities the module exposes. A script still has to create entries. The CLI import expects Contentful's own export shape, not raw Drupal JSON.Transform into the CLI or CMA shape. Do not post Drupal JSON at the CLI and hope.
ReferencespartialcriticalContentful's article says you create referenced entries first. Their example is authors before the posts that point at them.Order the load. Fail the run if a link points at an id you have not created.
HTML bodiespartialcriticalThe article says Drupal HTML should become Contentful rich text, using their conversion library, because rich text is JSON rather than an HTML blob.Convert a sample of each text format. Read the result in the Contentful editor.
FilespartialcriticalFiles have to be uploaded as Contentful assets and then linked. A JSON:API file URL is not an asset id.Upload assets first. Store the Drupal file id next to the asset id.
Users and permissionsmanualhighDrupal accounts do not become Contentful users. The article's path is a content migration, not an identity migration.Invite the editors you still need. Keep bylines as entries or as text, on purpose.
Views, blocks, and thememanualcriticalPresentation stays in your frontend. Contentful does not render a Drupal theme.Rebuild the routes in the frontend you chose. This playbook stops at the content load.
ModulesmanualhighThe article says to audit modules and find a Contentful app, or port behavior with the App Framework. That is a product decision, not an import.List modules that are in use. Mark each as an app, custom code, or dropped.
Revisions and unpublished workflowpartialhighDrupal revisions do not become Contentful snapshots unless you create entries in the states you want. Draft versus published is a Contentful step you run.Decide which revision is the one you publish. Do not publish the space by accident.
PathsmanualcriticalPath aliases are your frontend's routes now. Contentful does not host the old Drupal URLs by itself.Keep a redirect map on the host that still answers the domain.
03Field and feature mapping

Where each thing goes.

SourceDestinationMethodNotes
Content typeContentful content typemanualCreate it before the load.
Node idA stored Drupal id fieldtransformUse it to reconcile and to build links.
Text fieldSymbol, text, or rich texttransformHTML goes through the converter when the destination is rich text.
Entity referenceEntry linktransformCreate the target entry first.
File or imageAssettransformUpload, then link.
Taxonomy termEntry or a short text listmanualPick one model and stick to it.
AuthorEntry or textmanualNot a Contentful user login.
Path aliasFrontend route and a redirectmanualOwned by the site in front of Contentful.
View or blockNo destinationunsupportedRebuild in the frontend.
04Before you begin

Make the move recoverable.

Backup procedure

Create the source-of-truth backup

Keep Drupal restorable while Contentful receives a copy.

  1. Back up the database, sites directory, uploads, and custom code, as the user guide describes.
  2. Save a JSON:API extract of the types you will migrate.
  3. Export the empty Contentful content model with the CLI before the first import, so you can recreate the space shape.
  4. Record the management token's owner and its expiry.

Proof to capture: Drupal restores from the backup, and you have a CLI export of the content model from before entries were added.

Transformation · JSON:API, Contentful's HTML-to-rich-text library, and a script

Field map and rich text

Turn Drupal entities into Contentful entries without losing links.

  1. Read one content type from JSON:API.
  2. Convert HTML fields and record any node the library skips.
  3. Write entries only after their targets exist.
  4. Store the Drupal id on the entry.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

Transformation · Contentful CLI import, after the file matches an export shape

CLI load

Upload a transformed space export, or create entries through the CMA if you script that instead.

  1. Import into a non-production space or environment first.
  2. Compare entry counts by content type.
  3. Publish only the entries that passed the sample read.
  4. Keep the Drupal extract so you can rebuild the file.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

05Handle with care

The things most likely to hurt.

These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.

Transform

Links are created before their targets

criticallikely likelihood

The API rejects the entry, or the link is empty.

Consequence
A whole type fails late in the run.
Mitigation
Load targets first and fail on a missing id.

Stop if: Any required link is unresolved.

Transform

HTML is pasted into rich text

highpossible likelihood

The field contains a string of HTML instead of a rich text document.

Consequence
Editors cannot use the field, or the frontend renders tags as text.
Mitigation
Run the converter and open the entry.

Stop if: A sample body is still raw HTML.

Cutover

The production space is published early

criticalpossible likelihood

Draft content or the wrong revision is public.

Consequence
Visitors see unfinished entries.
Mitigation
Use a separate environment and publish on purpose.

Stop if: An entry is public before the sample check.

06Precise timeline

Do the work in this order.

Estimate forDrupal content types read from JSON:API and written into a prepared Contentful model.
Total elapsed15 to 40 business days
Active work50 to 120 hours
BufferAdd time for several content types, a large asset library, or a frontend you are building in parallel.
01
Days 1 to 5Map types and fields3 to 5 days
02
Days 5 to 7Back up Drupal and the model1 to 2 days
03
Days 7 to 18Load one type5 to 12 days
04
Days 18 to 25Load the rest and publish3 to 7 days
05
Days 25 to 40Watch the frontend5 to 15 days
  1. Days 1 to 5 · inventory

    Map types and fields

    10 to 20 hours active3 to 5 days elapsedEditors and developers waiting
    • List types, references, and text formats.
    • Create the Contentful model.

    Depends on: Drupal read access, Contentful admin

    Stop / go checkpoint

    Extract?

    Go when: Every field has a destination or a skip.

    Stop when: A reference has no target type.

  2. Days 5 to 7 · backup

    Back up Drupal and the model

    4 to 8 hours active1 to 2 days elapsedDatabase dump waiting
    • Back up Drupal.
    • Export the Contentful model with the CLI.

    Depends on: Approved model

    Stop / go checkpoint

    Transform a type?

    Go when: Both backups restore or re-import as an empty model.

    Stop when: The model export fails.

  3. Days 7 to 18 · pilot

    Load one type

    16 to 40 hours active5 to 12 days elapsedAsset uploads waiting
    • Convert one type.
    • Create targets first.
    • Read entries in the web app.

    Depends on: Verified backup

    Stop / go checkpoint

    Load the other types?

    Go when: Counts match and rich text opens cleanly.

    Stop when: Links or HTML fail.

  4. Days 18 to 25 · cutover

    Load the rest and publish

    10 to 24 hours active3 to 7 days elapsedFrontend deploy waiting
    • Freeze Drupal edits.
    • Load the final delta.
    • Publish the environment you checked.

    Depends on: Passed pilot

    Stop / go checkpoint

    Publish?

    Go when: Counts match and the frontend reads the space.

    Stop when: Drupal is still changing, or a type is short.

  5. Days 25 to 40 · observe

    Watch the frontend

    8 to 20 hours active5 to 15 days elapsedA publishing cycle waiting
    • Editors change one entry in Contentful.
    • Keep the Drupal backup.

    Depends on: Verified cutover

    Stop / go checkpoint

    Stop Drupal writes for good?

    Go when: Editors can publish, and the checks still pass.

    Stop when: An asset or a route fails.

07The point of change

Cut over with a way back.

Go live

Cutover

Publish the checked Contentful environment and stop Drupal edits.

Recommended window: A morning when you can point the frontend back at Drupal.

  1. Freeze Drupal.
  2. Re-read changed nodes and upsert them by Drupal id.
  3. Compare counts and a sample of rich text and assets.
  4. Publish that environment.
  5. Point the frontend at it and keep redirects on the old host.

Proof to capture: The frontend reads Contentful, entry counts match, and Drupal is unchanged since the freeze.

Return to safety

Rollback

Serve Drupal again.

Deadline: While the Drupal backup and host still exist.

  1. Point the frontend or DNS back at Drupal.
  2. Unpublish the Contentful environment if it went out by mistake.
  3. Export entries created only in Contentful.
  4. Review them before anyone retypes them into Drupal.
  5. Confirm the old URLs respond.

Proof to capture: Drupal is live again, and Contentful-only edits are listed.

Rollback immediately when
  • A content type count is short
  • A required asset 404s
  • Rich text is still HTML
  • A required link is empty
08Verification report

Prove the migration worked.

Every blocking check must pass. Capture the evidence before cleanup begins.

0%
Interactive report preview0 / 8 checks passed
PassIDCheckMethodExpected resultEvidence
V-01BlockingField mapRead the content type in Contentful against the map.Every required field exists.Model diff
V-02BlockingEntriesCompare Drupal entity counts with Contentful entries.Scoped types match.Count sheet
V-03BlockingReferencesOpen an entry with links.Targets exist and are the right ids.Link sample
V-04BlockingBodiesOpen a converted body in the editor and on the frontend.It is rich text, and the sample matches Drupal.Body sample
V-05BlockingFilesOpen a sample of assets anonymously.They match the Drupal files.Asset sample
V-06BlockingDrupal idFetch an entry by the stored Drupal id.It is unique.Id sample
V-07BlockingStateCheck draft versus published on a sample.Only the intended entries are public.State sample
V-08BlockingOld URLsRequest the old Drupal paths on the host that still owns the domain.Redirects land on the new routes.Redirect log
09Post-migration cleanup

Remove the scaffolding safely.

Safe after: Editors have published in Contentful for a cycle, and Drupal still restores from backup.

  1. Archive the JSON:API extract and the CLI model export.
  2. Revoke the management token you used for the load.
  3. Remove staging spaces you do not need.
  4. Keep Drupal until redirects and rollback are done.
  5. Note the library version you used for HTML conversion.
Sources and evidence

Verify against the primary material.

Platform behavior changes. Check these sources and the review dates above before executing a production migration.

  1. Drupal: JSON:API moduleAccessed 2026-11-05
  2. Contentful: CLI import and exportAccessed 2026-11-05
  3. Contentful: Drupal migration articleAccessed 2026-11-05
  4. Drupal User Guide: data backupsAccessed 2026-11-05