# contentful-import

> this tool allows you to import JSON dump exported by contentful-export

Latest version **10.5.2** (published 2026-09-11) · MIT license · 0 weekly downloads

## Install

```sh
npm install contentful-import
pnpm add contentful-import
yarn add contentful-import
bun add contentful-import
```

Provides the command `contentful-import`.

## Health

**Score 75/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 10.5.2 |
| Published | 2026-09-11 |
| First published | 2016-10-19 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=22 |
| Dependencies | 13 |
| Unpacked size | 596.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 103 |
| Author | Contentful |
| Maintainers | contentful-ecosystem |
| Keywords | contentful, contentful-import |

## Links

- npm: https://www.npmjs.com/package/contentful-import
- Repository: https://github.com/contentful/contentful-import
- Homepage: https://github.com/contentful/contentful-import#readme
- Issues: https://github.com/contentful/contentful-import/issues
- npm.io page: https://npm.io/package/contentful-import

## Dependencies (13)

- [joi](https://npm.io/package/joi.md) ^18.2.3
- [listr](https://npm.io/package/listr.md) ^0.14.3
- [yargs](https://npm.io/package/yargs.md) ^17.7.3
- [p-queue](https://npm.io/package/p-queue.md) ^6.6.2
- [bluebird](https://npm.io/package/bluebird.md) ^3.7.2
- [date-fns](https://npm.io/package/date-fns.md) ^4.4.0
- [lodash-es](https://npm.io/package/lodash-es.md) ^4.18.1
- [cli-table3](https://npm.io/package/cli-table3.md) ^0.6.5
- [@discoveryjs/json-ext](https://npm.io/package/@discoveryjs/json-ext.md) ^0.6.3
- [contentful-batch-libs](https://npm.io/package/contentful-batch-libs.md) ^9.7.0
- [contentful-management](https://npm.io/package/contentful-management.md) ^12.17.0
- [listr-update-renderer](https://npm.io/package/listr-update-renderer.md) ^0.5.0
- [listr-verbose-renderer](https://npm.io/package/listr-verbose-renderer.md) ^0.6.0

## Recent versions

- 10.5.2 (latest) — 2026-09-11
- 11.0.0-exo.9 (exo) — 2026-08-13
- 9.5.0-testing-publishing-to-github-packages.3 (testing-publishing-to-github-packages) — 2025-11-11
- 9.4.68-beta.1 (beta) — 2024-11-07
- 7.1.0-beta2 (next) — 2018-07-18
- 10.5.1 — 2026-09-11
- 10.5.0 — 2026-09-10
- 10.4.0 — 2026-09-10
- 10.3.0 — 2026-09-10
- 10.2.3 — 2026-09-09
- 10.2.2 — 2026-08-28
- 10.2.1 — 2026-08-28
- 10.2.0 — 2026-08-19
- 10.1.2 — 2026-08-17
- 10.1.1 — 2026-08-17
- … 486 more at https://npm.io/package/contentful-import/versions

## README

# Contentful import tool

[![npm](https://img.shields.io/npm/v/contentful-import.svg)](https://www.npmjs.com/package/contentful-import)
[![CI](https://github.com/contentful/contentful-import/actions/workflows/main.yaml/badge.svg)](https://github.com/contentful/contentful-import/actions/workflows/main.yaml)

[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)

[Contentful](https://www.contentful.com) provides a content infrastructure for digital teams to power content in websites, apps, and devices. Unlike a CMS, Contentful was built to integrate with the modern software stack. It offers a central hub for structured content, powerful management and delivery APIs, and a customizable web app that enable developers and content creators to ship digital products faster.

This library helps you to import files generated by [contentful-export](https://github.com/contentful/contentful-export) to a destination space.

## :exclamation: Usage as CLI

> We moved the CLI version of this tool into our [Contentful CLI](https://github.com/contentful/contentful-cli). This allows our users to use and install only one single CLI tool to get the full Contentful experience.
>
> Please have a look at the [Contentful CLI import command documentation](https://github.com/contentful/contentful-cli/tree/master/docs/space/import) to learn more about how to use this as command line tool.

## :cloud: Pre-requisites && Installation

### Pre-requisites

- Node >= 22

### Installation

```bash
npm install contentful-import
```

## :hand: Usage as a module

```javascript
const contentfulImport = require('contentful-import')

const options = {
  content: {entries:..., contentTypes:..., locales:...},
  spaceId: '<space_id>',
  managementToken: '<content_management_api_key>',
  ...
}

contentfulImport(options)
  .then(() => {
    console.log('Data imported successfully')
  })
  .catch((err) => {
    console.log('Oh no! Some errors occurred!', err)
  })
```

Using ESM:

```javascript
import spaceImport from "contentful-import";
```

or

```javascript
const contentfulImport = require('contentful-import')

const options = {
  contentFile: '/path/to/result/of/contentful-export.json',
  spaceId: '<space_id>',
  managementToken: '<content_management_api_key>',
  ...
}

contentfulImport(options)
  .then(() => {
    console.log('Data imported successfully')
  })
  .catch((err) => {
    console.log('Oh no! Some errors occurred!', err)
  })
```

## 💾 Usage as a CLI executable

1. Build the package:

```bash
$ npm run build
```

2. Execute the CLI tool by running the binary and passing the required parameters

```bash
$ ./bin/contentful-cli \
--space-id <space-id> \
--management-token <management-token> \
--content-file <content-file>
```

#### Import an environment

```javascript
const contentfulImport = require('contentful-import')

const options = {
  contentFile: '/path/to/result/of/contentful-export.json',
  spaceId: '<space_id>',
  managementToken: '<content_management_api_key>',
  environmentId: '<environment_id>',
  ...
}

contentfulImport(options)
...
```

## :gear: Configuration options

### Basics

#### `spaceId` [string] [required]

ID of the space to import into

#### `environmentId` [string] [default: 'master']

ID of the environment in the destination space

#### `managementToken` [string] [required]

Contentful management API token for the space to be imported to

#### `contentFile` [string]

Path to JSON file that contains data to be import to your space

#### `content` [object]

Content to import. Needs to match the expected structure (See below)

#### `timeout` [number]

Time between retries

#### `retryLimit` [number]

Maximum number of retries

### Filtering

#### `contentModelOnly` [boolean] [default: false]

Import content types only

#### `skipContentModel` [boolean] [default: false]

Skip importing of content types and locales

#### `skipLocales` [boolean] [default: false]

Skip importing of locales

#### `skipContentUpdates` [boolean] [default: false]

Skip updating existing content

#### `skipContentPublishing` [boolean] [default: false]

Skips content publishing. Creates content but does not publish it

#### `unpublishDraftLocales` [boolean] [default: false]

Unpublish locales that the content file marks as `draft` but that are still published in the destination.

Per-locale publishing is additive, so importing can add published locales but cannot demote one on its own. This only matters when importing over content that is already published — for a fresh import into a clean environment it makes no difference. Enable it to make repeated imports converge on exactly the state in the content file.

Note that this lets an import **unpublish** content in the destination, which is why it is opt-in.

### Assets

#### `uploadAssets` [boolean] [default: false]

Upload local asset files downloaded via the [downloadAssets](https://github.com/contentful/contentful-export#downloadassets-boolean) option of the export. Requires `assetsDirectory`

#### `skipAssetUpdates` [boolean] [default: false]

Skip updating existing assets

#### `assetsDirectory` [string]

Path to a directory with an asset export made using the [downloadAssets](https://github.com/contentful/contentful-export#downloadassets-boolean) option of the export. Requires `uploadAssets`

### Connection

#### `host` [string] [default: 'api.contentful.com']

The Management API host

#### `proxy` [string]

Proxy configuration in HTTP auth format: `host:port` or `user:password@host:port`

#### `rawProxy` [boolean]

Pass proxy config to Axios instead of creating a custom httpsAgent

#### `rateLimit` [number] [default: 7]

Maximum requests per second used for API requests

#### `headers` [object]

Additional headers to attach to the requests.

### Other

#### `errorLogFile` [string]

Full path to the error log file

#### `useVerboseRenderer` [boolean] [default: false]

Display progress in new lines instead of displaying a busy spinner and the status in the same line. Useful for CI.

#### `config` [string]

Path to a JSON file with the configuration options. This file will be merged with the options passed to the function. The options passed to the function will take precedence over the ones in the config file.

### Experience Orchestration

#### `includeExperienceOrchestration` [boolean] [default: true]

Flag controlling whether Experience Orchestration (ExO) entities — Design Tokens, Components, Experience Templates, Experience Fragments, Data Assemblies, and Experiences — are imported when present in the source content. Requires the `exoM1` entitlement on the destination space's organization. Set to `false` to opt out. See the "Experience Orchestration (ExO) entities" section below for what happens when the destination isn't entitled.

#### `skipExoVariants` [boolean] [default: false]

Skip importing nested Experience and Experience Fragment Optimization Variants. This can be useful when re-importing the same export because the upstream API generates new variant IDs on every create and cannot upsert by the source variant ID.

## :rescue_worker_helmet: Troubleshooting

### Proxy

Unable to connect to Contentful through your Proxy? Try to set the `rawProxy` option to `true`.

```javascript
contentfulImport({
  proxy: 'https://cat:dog@example.com:1234',
  rawProxy: true,
  ...
})
```

### Embargoed Assets

If a space is configured to use the [embargoed assets feature](https://www.contentful.com/help/media/embargoed-assets/), export with `downloadAssets: true` and import with `uploadAssets: true` and `assetsDirectory` pointing to the directory generated by the export. Embargoed asset URLs cannot be processed directly during import; the importer now fails before making API calls and prints the required options when the local upload options are missing.

```javascript
const contentfulImport = require('contentful-import')

const options = {
  contentFile: '/path/to/result/of/contentful-export.json',
  spaceId: '<space_id>',
  managementToken: '<content_management_api_key>',
  uploadAssets: true,
  assetsDirectory: '/path/to/exported-assets'
}

contentfulImport(options)
```

## :card_file_box: Expected input data structure

The data to import should be structured like this:

```json
{
  "contentTypes": [],
  "entries": [],
  "assets": [],
  "locales": [],
  "webhooks": [],
  "roles": [],
  "tags": [],
  "editorInterfaces": [],
  "designTokens": [],
  "components": [],
  "experienceTemplates": [],
  "dataAssemblies": [],
  "experienceFragments": [],
  "experiences": [],
  "releases": []
}
```

Note: `tags` are not available for all users. If you do not have access to this feature, any tags included in your import data will be skipped.

The `designTokens`, `components`, `experienceTemplates`, `dataAssemblies`, `experienceFragments`, and `experiences` keys are Experience Orchestration (ExO) entities — see the "Experience Orchestration (ExO) entities" section below.

The `releases` key is subject to the [Releases](https://www.contentful.com/help/releases/) feature — see the "Releases" section below.

## :test_tube: Experience Orchestration (ExO) entities

> **Experimental:** ExO entities (`designTokens`, `components`, `experienceTemplates`, `dataAssemblies`, `experienceFragments`, `experiences`) are `@internal` and considered experimental. Their shape and import behavior are subject to change without notice.

ExO import is on by default (`includeExperienceOrchestration: true`) — for the CLI and the module API alike. Pass `includeExperienceOrchestration: false` (`--include-experience-orchestration=false` on the CLI) to opt out.

Optimization Variant import is on automatically when the source contains nested variants. Pass `skipExoVariants: true` (or `--skip-exo-variants`) to leave them out of the import. When variants are imported, a warning is logged because each run creates fresh destination variant IDs and re-importing can create duplicates.

```javascript
import contentfulImport from 'contentful-import'

const options = {
  contentFile: '/path/to/result/of/contentful-export.json',
  spaceId: '<space_id>',
  managementToken: '<content_management_api_key>',
  includeExperienceOrchestration: false, // opt out; omit to import ExO entities when present (the default)
  ...
}

await contentfulImport(options)
```

If your source content has no ExO entities at all — true for anyone not using ExO — this default is a complete no-op. The destination-entitlement check in `lib/tasks/get-destination-data.ts` only runs if the source data actually contains ExO entities (`sourceData.designTokens?.length`, etc.); with nothing to check, no extra API calls happen and nothing extra gets logged. Behavior is identical either way for imports that don't involve ExO content.

Requires the `exoM1` entitlement on the destination space's organization. [contentful-cli](https://github.com/contentful/contentful-cli)'s `space import` command doesn't expose this option at all yet, so ExO import isn't reachable through that separate CLI regardless of default.

If the destination space isn't entitled and the source data does contain ExO entities, ExO import for that space is skipped and the rest of the content (content types, entries, assets, etc.) still imports normally — but the missing-entitlement notice is logged at error level, not warning. That means `contentfulImport()` still rejects with a `ContentfulMultiError` at the end, even though the non-ExO content imported successfully. Don't treat a rejected promise as proof the whole import failed — check `err.errors` (or the `errorLogFile`) for `Experience Orchestration (ExO) is not enabled for this space` before assuming something is actually broken.

### Import order

ExO entities are created and published in dependency order, then unpublished in reverse order once every other import step has finished:

1. Data Assemblies — create, then publish
2. Design Tokens — create only (no publish/unpublish step; a Design Token is live as soon as it's created or updated)
3. Components — create, then publish
4. Experience Templates — create, then publish
5. Experience Fragments — create, then publish
6. Experiences — create, then publish
7. Experience Optimization Variants — create, then publish/archive (only if the source has any; see below)
8. Experience Fragment Optimization Variants — create, then publish/archive (only if the source has any; see below)
9. Unpublish pass, in reverse: Experiences → Experience Fragments → Experience Templates → Components → Data Assemblies

An entity that's published in the source is published in the destination on import. An entity that's unpublished (or removed) in the source but still published in the destination is unpublished on re-import — this propagates in both directions, so reverting a published ExO entity back to draft in the source and re-running the import will unpublish it in the destination too.

### Optimization Variants

Experiences and Experience Fragments each support **Optimization Variants** — alternate personalization versions nested onto their parent (`experience.optimizationVariants` / `experienceFragment.optimizationVariants`), not a flat top-level array like the other six ExO entity types. A variant's `sys.id` is borrowed from its parent rather than being globally unique — see the export tool's own doc ([contentful-export's ExO doc](https://github.com/contentful/contentful-export/blob/main/docs/exo-export.md#optimization-variants)) for the full rationale.

Two behaviors are worth calling out explicitly because they differ from every other ExO entity type:

- **No ID preservation.** Every other ExO entity is created via upsert-with-known-ID. Variants can't be: the upstream API's create endpoint always server-generates a fresh ID, and its update endpoint 404s on an unknown ID instead of creating one. Every import run creates brand-new destination variants — re-running an import with variants in the source data creates additional variants rather than updating existing ones.
- **The API's synthetic "default" entry is filtered out.** The upstream list endpoint always leads with an entry representing the parent's own base view (`sys.variantType: 'default'`) — not a real variant. `contentful-export` already excludes it; `contentful-import` filters it again defensively for older export files.

### URN rewriting / backward compatibility

- Export files taken before the ExO entity rename (`ComponentType` → `Component`, `Fragment` → `ExperienceFragment`, `Template` → `ExperienceTemplate`) are upgraded automatically on import, including the corresponding resource-link `linkType`s and URN path segments. This upgrade is upgrade-only (there's no downgrade path) and idempotent, so it's safe to run against already-upgraded data.
- Export files that predate ExO entirely (no ExO keys, or empty ExO arrays) import unchanged — no extra configuration is needed to import older export files.

## :package: Releases

> **Only `Release.v2` ("Releases") is supported. `Release.v1` ("Launch") is not supported.**
>
> **The destination space's organization must have the [Releases](https://www.contentful.com/help/releases/) entitlement enabled.** Releases is a premium/paid feature — if the destination isn't entitled, importing releases will fail.

If your source content includes a `releases` key, each entry is checked for `sys.schemaVersion`. Only releases with `sys.schemaVersion: "Release.v2"` are imported; any `Release.v1` (Launch) release is skipped and logged as an error, since its payload shape isn't compatible with the `Release.v2` create/update API.

A release that already exists in the destination space at the source's exact `sys.id` is updated; otherwise one is created. There is no separate publish/unpublish step for releases — a release's own `entities` collection already carries the per-entity `publish`/`unpublish` action to take when the release itself is applied.

**Releases have no ID-preserving create, unlike every other importable entity.** The Releases API always server-generates a release's `sys.id` on create — there is no way to request a specific ID. So the update path above only fires if a release already exists in the destination at the source's exact ID (for example, an environment cloned from the source) — which an import run can never produce on its own. Practically: re-importing the same source data creates additional releases rather than updating the ones from a prior run. If you need to re-run an import that includes releases, delete or archive the previously-imported ones first to avoid duplicates.

## :bulb: Importing to a space with existing content

- Both source space and destination space must share the same content model structure. In order to achieve that, please use [contentful-migration](https://www.npmjs.com/package/contentful-migration).
- Content transformations are also not supported, please use [contentful-migration](https://www.npmjs.com/package/contentful-migration).
- Entities existence are determined based on their ID:
  - If an entity does not exist in the destination space, it will be created.
  - If an entity already exists in the destination space, it will be updated.
- Publishing strategy:
  - If an entity is in draft, it will be created as draft in the destination space.
  - If an entity is published and has pending changes (updated) in the source space, it will be published with the latest changes in the destination space.
  - If an entry or asset was published for only some of its locales, only those locales are published in the destination space. This is read from `sys.fieldStatus` in the content file, which `contentful-export` writes automatically — existing export files already contain it, so no re-export is needed. Content files without `sys.fieldStatus` are published as a whole, as before.

## :warning: Limitations

- This tool currently does **not** support the import of space memberships.
- This tool currently does **not** support the import of roles.
- This tool is expecting the target space to have the same default locale as your previously exported space.
- Imported webhooks with credentials will be imported as normal webhooks. Credentials should be added manually afterwards.
- Imported webhooks with secret headers will be imported without these headers. Secret headers should be added manuall afterwards.
- If you have custom UI extensions, you need to reinstall them manually in the new space.
- `Release.v1` ("Launch") releases are not supported for import — only `Release.v2` ("Releases") releases are imported; see the "Releases" section above.
- Per-locale publish state is restored, with three caveats:
  - The destination has to support [locale-based publishing](https://www.contentful.com/help/localization/locale-based-publishing/), which means two things: the organization is entitled to it (it is not on every plan), and the destination environment has "Locale-based (un)publishing" selected under **Settings > Locales > Publishing options** — the default is "Publish all locales". The import checks the entitlement up front and detects an environment that publishes whole entities anyway, and in either case logs a warning and falls back to publishing every locale, exactly as it did before this feature. The import itself does not fail.
  - A locale that was `changed` in the source space (published, with newer draft edits on top) is imported as `published`. Reconstructing `changed` needs two separate writes, which an import cannot express.
  - Locale-scoped publishing only adds published locales. If an entry in the destination space is already published for a locale that should be draft, that locale stays published by default — importing into a clean environment is unaffected. Set [`unpublishDraftLocales`](#unpublishdraftlocales-boolean-default-false) to demote those locales as well.
- Locales that are published in the source space but do not exist in the destination environment are skipped. If none of an entity's published locales exist in the destination, the entity is left unpublished and a warning is logged.

## :memo: Changelog

Read the [releases](https://github.com/contentful/contentful-import/releases) page for more information.

## :scroll: License

This project is licensed under MIT license

[1]: https://www.contentful.com

## For AI Agents

<!-- Generated by seed-golden-context | Last updated: 2026-05-05 -->
If you are an AI coding agent working in this repository, read [AGENTS.md](./AGENTS.md) first. It tells you where to find architectural context, development setup, decision records, and repo-specific rules.

---
_Source: https://npm.io/package/contentful-import · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
