---
title: "Migrate from Contentstack CLI V1 to V2"
description: "Upgrade the Contentstack CLI from V1 to V2 with a flag-by-flag mapping, export and import format changes, a pre-upgrade checklist, and fixes for silent failures."
url: "https://www.contentstack.com/docs/headless-cms/cli-v1-to-v2-migration-guide"
product: "Contentstack"
doc_type: "guide"
audience:
  - developers
  - admins
version: "current"
last_updated: "2026-11-06"
---

# Migrate from Contentstack CLI V1 to V2

## Overview

This guide applies if you are upgrading Contentstack CLI from version 1.x.x to 2.x.x.

V2 requires Node.js 22+, routes all publish operations through Nested Reference Publishing (NRP), removes several flags and command aliases with no runtime warning, and changes the on-disk format of exports (per-UID files replace aggregate JSON files like schema.json and globalfields.json).

You get a flag-by-flag mapping for every removed command, the export and import file-format changes to check in your tooling, a pre-upgrade checklist, and the failure modes in this upgrade that produce no error output. The fixes for those failure modes are in the [CLI troubleshooting FAQs](/docs/headless-cms-cli-troubleshooting/faqs).

This guide covers CLI-only changes. It does not cover Contentstack platform or API changes.

## Quick Decision Guide

Find the rows that match how you use the CLI, then read only those sections.

If you

Impact

Read

Run csdx by hand, with no scripts

Low

[Prerequisites](#prerequisites), [Command Aliases Removed](#command-aliases-removed)

Script export or import

High

[cm:stacks:export](#cmstacksexport), [cm:stacks:import](#cmstacksimport), [Compatibility of V1 Artifacts with V2](#compatibility-of-v1-artifacts-with-v2)

Export more than one branch

High

[cm:stacks:export](#cmstacksexport). V2 exports only main by default and writes flat output, so exporting two branches to one directory overwrites the first.

Parse stdout in CI

High

[Default Output: Progress Bars Replace Console Logs](#default-output-progress-bars-replace-console-logs)

Publish or unpublish in bulk

High

[cm:stacks:bulk-entries](#cmstacksbulk-entries), [cm:stacks:bulk-assets](#cmstacksbulk-assets), [All Publish Operations Now Use NRP](#all-publish-operations-now-use-nrp)

Authenticate with \--auth-token or an alias

Medium

[Authentication Changes](#authentication-changes)

Use launch:\* or cm:entries:migrate-html-rte

Medium

[Plugin Changes](#plugin-changes). Both are separate installs in V2.

Use cm:bootstrap

Medium

[cm:bootstrap](#cmbootstrap). V2 removes 13 app configs.

Import the composable-studio module

Medium

[Authentication Changes](#authentication-changes). Basic Auth is the only supported path.

Maintain a custom CLI plugin or import config

Medium

[Removed Import Config Keys (Custom Plugins and Config Files)](#cmstacksimport), [Node.js 22+](#nodejs-22)

Use tsgen or content-type:\*

Low

[Type Mapping Reference](#type-mapping-reference). Flag renames only.

Commands not listed above need no changes beyond the flag renames in [Type Mapping Reference](#type-mapping-reference).

Before you upgrade, work through the [Pre-Upgrade Checklist](#pre-upgrade-checklist). If a command reports success but produces no data, read the [CLI troubleshooting FAQs](/docs/headless-cms-cli-troubleshooting/faqs) first. Several failure modes in this upgrade produce no error output.

### Compatibility of V1 Artifacts with V2

Use this table if you already upgraded and need to know whether an existing export, config, or token still works.

V1 artifact

Works with V2?

What to do

V1 export, content types

Yes

Nothing. V1 writes per-UID files (along with schema.json), which V2 continues to read.

V1 export, global fields

**No, skipped. The pre-import audit then offers to remove Global field fields**

Re-export with V2 before importing. See Global Fields Silently Skipped on Import.

V1 multi-branch export

**No, imports nothing**

Point \--data-dir at the branch subfolder. See V1 Multi-Branch Export Produces an Empty Import.

V1 export, audited with V2

**No, reports a false clean**

Re-export with V2 before auditing. See cm:stacks:audit Reports Zero Global-Field Issues on a V1 Export (False Clean).

V1 show-console-logs config

**No, silently ignored**

Re-run csdx config:set:log --show-console-logs. See V1 Console Log Config Silently Ignored After Upgrade.

Saved management tokens

Yes

Nothing. Tokens carry over with no re-authentication.

branches.json, export-info.json, schema.json, globalfields.json

Not written by V2

Remove any pipeline step that reads them. See [cm:stacks:export](#cmstacksexport).

## Prerequisites

### Node.js 22+

V2 requires Node.js \>=22.0.0.

If you need to upgrade, run:

```
nvm install 22
nvm alias default 22   # makes 22 the permanent default, not just for this shell session
nvm use 22
```

**Warning:** On Node 18 or 20, the npm install -g @contentstack/cli completes with EBADENGINE warnings and appears to succeed, but the CLI fails at runtime. Upgrade Node first, then install.

### Install V2

```
npm install -g @contentstack/cli@2
```

Using **yarn** or **pnpm**:

```
yarn global add @contentstack/cli@2
pnpm add -g @contentstack/cli@2
```

Verify the upgrade succeeded:

```
csdx --version
```

The output shows a 2.x version, such as 2.0.2.

**Warning:** npm install -g replaces the csdx binary in place. A roughly **30-second** window exists during installation where csdx is unavailable. For continuous integration (CI) pipelines, run the install and the CLI commands in the same pipeline step. Do not rely on a pre-installed binary from a prior step.

On a 2.x beta, upgrade directly to the latest 2.x release with npm install -g @contentstack/cli@2.

> **Note:** Verify Node 22 in Every Environment
> 
> Run this check on every environment where the CLI runs, including CI and continuous delivery (CD) pipelines, not only your local machine:
> 
> *   Dev machines
> *   CI/CD runners
> *   Docker base images (pin to the Node 22 LTS tag)

## Type Mapping Reference

The table below lists every flag rename and removed short character across every command. Rows that repeat the same V1 and V2 flag name had only their short character removed. Rows marked "use OAuth" mean you authenticate with Open Authorization (OAuth) login (csdx auth:login --oauth) instead of the removed flag.

Command

V1 Flag

V1 Short

V2 Flag

V2 Short

cm:stacks:export

\--stack-uid

\-s

\--stack-api-key

\-k

\--data

None

\--data-dir

\-d

\--management-token-alias

None

\--alias

\-a

\--auth-token

\-A

_(removed, use OAuth +_ \--alias_)_

None

\--module

\-m

\--module

None

\--content-types

\-t

\--content-types

None

\--branch

\-B

\--branch

None

cm:stacks:import

\--stack-uid

\-s

\--stack-api-key

\-k

\--data

None

\--data-dir

\-d

\--management-token-alias

None

\--alias

\-a

\--auth-token

\-A

_(removed, use OAuth +_ \--alias_)_

None

\--module

\-m

\--module

None

\--backup-dir

\-b

\--backup-dir

None

\--branch

\-B

\--branch

None

\--skip-app-recreation

None

_(removed, no replacement)_

None

cm:stacks:import-setup

\--branch

\-B

\--branch

None

cm:stacks:bulk-entries

\--api-version

None

_(removed)_

None

cm:stacks:bulk-taxonomies

\--api-version

None

_(removed)_

None

cm:stacks:seed

\--stack

\-s

\--stack-api-key

\-k

\--repo

\-r

\--repo

None

\--org

\-o

\--org

None

\--fetch-limit

\-l

_(removed)_

None

cm:stacks:migration

\--branch

\-B

\--branch

None

\--authtoken

\-A

_(removed, use OAuth +_ \--alias_)_

None

\--filePath

\-n

\--file-path

None

\--config-file

None

_(removed, use_ \--config_)_

None

\--api-key

\-k

\--stack-api-key

\-k

\--management-token-alias

None

\--alias

\-a

\--multi

None

\--multiple

None

cm:stacks:validate-regex

\--contentType

\-c

\--contentType

None

\--filePath

\-f

\--filePath

None

\--globalField

\-g

\--globalField

None

cm:bootstrap

\--appName

\-a

\--app-name

None

\--directory

\-d

\--project-dir

None

\--app-type

None

_(removed)_

None

\--appType

\-s

_(removed)_

None

auth:tokens:add

\--delivery

\-d

\--delivery

None

\--management

\-m

\--management

None

\--token

\-t

\--token

None

\--api-key

None

\--stack-api-key

\-k

\--branch

None

_(removed)_

None

\--force

\-f

\--yes

\-y

auth:tokens:remove

\--ignore

\-i

_(removed)_

None

auth:logout

\--force

\-f

\--yes

\-y

config:set:region

\--cda

\-d

\--cda

None

\--cma

\-m

\--cma

None

\--name

\-n

\--name

None

tsgen

\--token-alias

\-a

\--alias

\-a

\--output

\-o

\--output

None

\--prefix

\-p

\--prefix

None

\--doc

\-d

\--doc

None

app:create

\--name

\-n

\--name

None

migrate:convert

\--output

\-o

\--output

None

\--master-locale

\-m

\--master-locale

None

\--affix

\-a

\--affix

None

migrate:export

\--output

\-o

\--output

None

content-type:audit

\--stack

\-s

\--stack-api-key

\-k

\--token-alias

\-a

\--alias

\-a

\--content-type

\-c

\--content-type

None

content-type:compare

\--stack

\-s

\--stack-api-key

\-k

\--token-alias

\-a

\--alias

\-a

\--content-type

\-c

\--content-type

None

\--left

\-l

\--left

None

\--right

\-r

\--right

None

content-type:compare-remote

\--origin-stack

\-o

\--origin-stack

None

\--remote-stack

\-r

\--remote-stack

None

\--content-type

\-c

\--content-type

None

content-type:details

\--stack

\-s

\--stack-api-key

\-k

\--token-alias

\-a

\--alias

\-a

\--content-type

\-c

\--content-type

None

\--path

\-p

\--path

None

content-type:diagram

\--stack

\-s

\--stack-api-key

\-k

\--token-alias

\-a

\--alias

\-a

\--output

\-o

\--output

None

\--direction

\-d

\--direction

None

\--type

\-t

\--type

None

content-type:list

\--stack

\-s

\--stack-api-key

\-k

\--token-alias

\-a

\--alias

\-a

\--order

\-o

\--order

None

cm:stacks:audit

\--reference-only

None

_(removed)_

None

cm:stacks:audit:fix

\--reference-only

None

_(removed)_

None

**Behavior Change: cm:stacks:migration configuration flags** In V1, \--config took inline configuration and \--config-file took a file path. In V2, \--config takes the file path, inline configuration moved to the new \--inline-config flag, and \--config-file is removed. This is the one flag in the CLI that kept its name and changed its meaning, so a V1 script passing inline values to \--config is read as a file path rather than failing outright.

## Global CLI Behavior Changes

### Authentication Changes

V2 removes the token-passing flags. You authenticate once, then reference a stored alias.

V1

V2

\--auth-token / \-A on export and import

Removed. Run csdx auth:login, then pass \--alias.

\--authtoken / \-A on cm:stacks:migration

Removed. Run csdx auth:login, then pass \--alias.

\--management-token-alias on export and import

\--alias

\--token-alias on tsgen and content-type:\*

\--alias

\--api-key on auth:tokens:add

Removed. Use \--stack-api-key (\-k).

\--branch on auth:tokens:add

Removed with no replacement.

**Saved tokens carry over.** Management tokens added with csdx auth:tokens:add under V1 are available immediately after upgrading. You do not need to re-authenticate. See [Tokens and Config Carry Over Automatically](#tokens-and-config-carry-over-automatically).

**The composable-studio import module requires Basic Auth.** V2 skips this module when you authenticate with a management token or with OAuth. V2 prints a skip message rather than an error:

```
Skipping Studio project import when using management token
```

```
Skipping Studio project import when using OAuth authentication
```

Authenticate with username and password instead. Basic Auth is the only supported path for this module:

```
csdx auth:login -u <EMAIL> -p <PASSWORD>
```

### Default Output: Progress Bars Replace Console Logs

Behavior

V1

V2

Output format

Text printed line-by-line to stdout as operations run

Visual progress bars render in the terminal

Console log output

Printed live to stdout, parseable by scripts and CI

Suppressed by default

End-of-run output

Accumulated text output, no separate summary

Shows only a summary and a log file path

**Effect:** Any script or CI pipeline that parses stdout for success or failure signals receives different output. V2 does not exit non-zero or throw because of this. Whether a log line still reaches the console depends on its level:

Log level

Reaches the console when progress bars are active

error, warn

Yes, always

info, success, debug

No, suppressed

A script that parses stdout for a suppressed line finds nothing, not an error.

**CI environments:** By default, V2 shows progress bars and hides info and success log lines for export, import, audit, import-setup, clone and bulk operations. If your CI pipeline reads those lines, turn console logs on:

```
csdx config:set:log --show-console-logs
```

See [config:set:log](#configsetlog) for the full flag reference.

**Log file location:** V2 writes logs to a logs/ directory in whichever folder you ran the CLI from (for example, ./logs/). Set the CS\_CLI\_LOG\_PATH environment variable or run csdx config:set:log --path <dir> to redirect logs.

### Deprecated Flags Removed

V2 raises no runtime warning when a deprecated flag stops working, unlike V1. Audit your scripts before upgrading.

**Before (V1):**

```
csdx cm:stacks:export --stack-uid blt123
```

This prints a deprecation warning, then runs.

**After (V2):**

```
csdx cm:stacks:export --stack-uid blt123
```

```
ERROR: Nonexistent flag: --stack-uid
```

The same applies to every other deprecated flag (\--data, \-s, \-B, and similar).

### Short Flags Cleaned Up

V2 systematically removes single-character short flags that conflicted with global CLI flags or were ambiguous across commands. In every case the long form still works. See each command section for the specific characters removed.

### All Publish Operations Now Use NRP

In V2, all publish operations, including entry, asset, and taxonomy publishes triggered during import and all bulk publish and unpublish commands, go through the Nested Reference Publishing (NRP) API. V1 did not use NRP for import. For bulk publish, V1 cm:stacks:bulk-entries and cm:stacks:bulk-taxonomies accepted an \--api-version flag.

**What changed:**

Command

V1

V2

cm:stacks:import (auto-publish)

Did not use NRP

Uses NRP for all entry, asset, and taxonomy publishes

cm:stacks:bulk-entries

Accepted \--api-version (default 3.2)

Always uses NRP, \--api-version flag removed

cm:stacks:bulk-assets

No \--api-version flag

Always uses NRP

cm:stacks:bulk-taxonomies

Accepted \--api-version (default 3.2)

Always uses NRP, \--api-version flag removed

**Impact:** Your stack must have NRP enabled. V2 has no flag to run publish operations without NRP.

**Note:** Passing \--api-version to cm:stacks:bulk-entries or cm:stacks:bulk-taxonomies in V2 causes an immediate error: ERROR: Nonexistent flag: --api-version.

### Command Aliases Removed

V2 removes several short-form aliases that V1 used:

Removed Alias

V2 Replacement

csdx cm:export

csdx cm:stacks:export

csdx cm:import

csdx cm:stacks:import

csdx cm:import-setup

csdx cm:stacks:import-setup

csdx tokens

csdx auth:tokens:list

csdx cm:seed

csdx cm:stacks:seed

csdx audit

csdx cm:stacks:audit

csdx audit:fix

csdx cm:stacks:audit:fix

csdx cm:migration

csdx cm:stacks:migration

## Plugin Changes

### launch Plugin: Now Opt-In

V2 no longer bundles launch:\* commands in the CLI. When you run any launch:\* command, V2 prints a guided error with the install instruction and exits with code 127.

**Affected commands:** launch, launch:deployments, launch:environments, launch:functions, launch:logs, launch:open, launch:rollback

**No prior equivalent required:** these commands existed bundled in V1. V2 keeps the same commands available as an installable plugin.

**Before:** the launch plugin ships bundled with the CLI in V1. You need no install step.

**After:**

```
csdx plugins:install @contentstack/cli-launch
```

### migrate-rte Plugin: Now Opt-In

V2 no longer bundles cm:entries:migrate-html-rte in the CLI. As with launch, when you run it V2 prints a guided error with the install instruction and exits with code 127.

**Affected commands:** cm:entries:migrate-html-rte

**Before:** the migrate-rte plugin ships bundled with the CLI in V1. You need no install step.

**After:**

```
csdx plugins:install @contentstack/cli-cm-migrate-rte
```

Docs: [Migrate content from HTML RTE to JSON RTE](/docs/headless-cms/cli-migrate-content-from-html-rte-to-json-rte)

## Post-Upgrade Behavior

### Tokens and Config Carry Over Automatically

V2 carries over your existing saved tokens (management tokens added with csdx auth:tokens:add) automatically. You do not need to re-authenticate after upgrading.

V2 also carries over other stored config (proxy settings, region config) unchanged.

**Exception:** the console log setting. V2 uses a different internal key and silently ignores the V1 setting (see V1 Console Log Config Silently Ignored After Upgrade). If you ran this in V1, re-run it after upgrading:

```
csdx config:set:log --show-console-logs
```

## Gradual Migration

npm global install allows only one active version per Node environment. If you need V1 available during testing, install it under a different nvm Node version. For example:

```
nvm install 22 && nvm use 22 && npm install -g @contentstack/cli@1.x
nvm install 24 && nvm use 24 && npm install -g @contentstack/cli@2
```

**What this does not do:** nvm switches which install is active, it does not isolate CLI state. Both versions read the same saved tokens and the same region and proxy config described above, so signing out or reconfiguring in one affects the other. Only the console log setting is not shared, per the exception above.

## Command Reference

### cm:stacks:export

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference). Authentication flags are covered in [Authentication Changes](#authentication-changes).

**Before:**

```
csdx cm:stacks:export -s blt123 --data ./export -m content-types -t blog article -B main
```

**After:**

```
csdx cm:stacks:export --stack-api-key blt123 --data-dir ./export --module content-types --content-types blog article --branch main
```

**Behavior Change: Branch Export Writes Flat Output**

**V1:** When you omit \--branch, V1 exports all branches. V1 nests the output under exportDir/<branch-uid>/... for each branch.

**V2:** Two independent changes apply:

1.  **Default branch:** When you omit \--branch, V2 exports only the branch named main. If no main branch exists, the command errors.
2.  **No branch subfolder, always:** Even when you specify \--branch, V2 writes output flat to exportDir/... with no <branch-uid>/ subfolder. This applies regardless of how you select the branch.

**Impact for multi-branch stacks:** You must export each branch to a separate \--data-dir. If you export two branches to the same directory, the second export overwrites every file with a matching path and leaves the rest, so the folder holds a mix of both branches. V2 prints only a warning, The export directory is not empty. Existing files in this folder may be overwritten., and continues.

Use a separate \--data-dir per branch:

```
csdx cm:stacks:export --branch main       --data-dir ./export-main    --stack-api-key bltXXX
csdx cm:stacks:export --branch feature-x  --data-dir ./export-feature --stack-api-key bltXXX
csdx cm:stacks:export --branch-alias prod --data-dir ./export-prod     --stack-api-key bltXXX
```

**branches.json removed:**

*   V1 wrote a branches.json file to the export root listing all branches at export time.
*   V2 does not write this file, and raises no error. If your import pipeline or post-export tooling reads branches.json, remove that step.

**export-info.json No Longer Written**

V1 wrote export-info.json to the export directory containing { "contentVersion": 2, "logsPath": "..." }. V2 does not write this file. If your pipeline checks for this file or reads contentVersion from it, remove that step.

**content\_types/schema.json Removed**

**Warning:** A pipeline or script that reads export/content\_types/schema.json fails on a V2 export with no error message, because the file does not exist in a V2 export.

V1 wrote a combined content\_types/schema.json with all content type schemas in one array. V2 only writes individual content\_types/<uid>.json files. V2 drops the aggregate file entirely.

**Before:**

```
cat export/content_types/schema.json
```

**After:**

```
ls export/content_types/*.json
```

**Global Fields Format Changed (Per-File)**

**Warning:** If any pipeline or script reads export/global\_fields/globalfields.json, it fails on a V2 export. The file does not exist.

**Before:** V1 stores all global fields in one file.

```
export/global_fields/globalfields.json
```

**After:** V2 stores one file per global field UID.

```
export/global_fields/my_header.json
export/global_fields/my_footer.json
export/global_fields/shared_banner.json
```

Update any tooling that reads globalfields.json to iterate per-UID files instead.

**Behavior Change: Module Flag Now Validated, studio Renamed**

**Module validation:**

*   **V1:** an invalid \--module value is not checked upfront. The command fails partway through the operation, after work has already started.
*   **V2:** the CLI validates \--module against an explicit allowed-values list before any operation starts, and fails immediately with a clear error.

V2 renames V1's \--module studio value to \--module composable-studio. The old value fails:

```
Error: Expected --module=studio to be one of: stack, assets, locales, ...composable-studio
```

**Before:**

```
csdx cm:stacks:export --module studio
```

**After:**

```
csdx cm:stacks:export --module composable-studio
```

V2 also adds two export targets that V1 does not have: publishing-rules, personalize. Both are also supported on import (see [cm:stacks:import](#cmstacksimport)).

### cm:stacks:import

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference). Authentication flags are covered in [Authentication Changes](#authentication-changes). One removed flag has no replacement at all:

Removed

V2 Replacement

\--skip-app-recreation

**Removed with no replacement**

**Before:**

```
csdx cm:stacks:import -s blt123 --data ./export -b ./backup -B main
```

**After:**

```
csdx cm:stacks:import --stack-api-key blt123 --data-dir ./export --backup-dir ./backup --branch main
```

> **Warning:** V2 removes \--skip-app-recreation completely, with no replacement. Remove it from all import scripts.
> 
> \--skip-taxonomy-publish is a **new, unrelated** flag (see [Taxonomy Publishing](#taxonomy-publishing)). It does not replace \--skip-app-recreation.

The following flags exist in **both V1 and V2** and require no migration:

*   \--branch-alias
*   \--skip-audit
*   \--exclude-global-modules
*   \--replace-existing
*   \--skip-existing
*   \--import-webhook-status
*   \--personalize-project-name
*   \--skip-assets-publish
*   \--skip-entries-publish

Of these, \--skip-assets-publish and \--skip-entries-publish interact with a real behavior change: when unset, the publish that runs now goes through NRP (see [All Publish Operations Now Use NRP](#all-publish-operations-now-use-nrp)). The flag's own skip or no-skip behavior is unchanged.

**Behavior Change: Module Flag Validates Against a Strict List**

Same as export: V2 validates \--module on import before any operation begins. \--module studio fails. Use \--module composable-studio instead. V2 adds \--module variant-entries as a new valid value that V1 does not have.

**Behavior Change: Importing a V1 Export Silently Skips Global Fields**

V2's importers use per-UID file readers that explicitly ignore aggregate files. The impact differs between modules because V1 export behavior differs:

Module

V1 export writes

V2 importer reads

Impact on V1 export

Content types

Individual <uid>.json files **and** schema.json

Per-UID files only (ignores schema.json)

**No impact**, per-UID files exist, content types import correctly

Global fields

globalfields.json only (no individual files)

Per-UID files only (ignores globalfields.json)

**Silently skipped**, no per-UID files exist in a V1 export

**Impact:** Running V2 import on a V1 export skips **all global fields**. The screen shows no error, because the CLI writes No global fields found in directory to the log file only. Before it imports, the CLI runs an audit fix that treats every Global field field in your content types as a broken reference, and asks whether to remove them. Answer No, and do not pass \--yes, when you import a V1 export.

**Resolution:** Re-export your stack with V2 before importing. If the source stack no longer exists, write each object in global\_fields/globalfields.json to its own global\_fields/<uid>.json file, then import. No released CLI tool performs this split.

See Global Fields Missing After Importing a CLI V1 Export with CLI V2 in the [CLI troubleshooting FAQs](/docs/headless-cms-cli-troubleshooting/faqs). Symptom: the import command reports success, and zero global fields exist in the target stack afterward.

**Behavior Change: V1 Multi-Branch Export Auto Detection Removed**

V1 import auto-detected the branch by reading branches.json at the export root and navigating to the correct <branch-uid>/ subfolder. V2 removes this selectBranchFromDirectory logic.

**Before:**

```
csdx cm:stacks:import --data-dir ./my-export
```

V1 reads branches.json and auto-navigates to ./my-export/main/.

**After:**

```
csdx cm:stacks:import --data-dir ./my-export/main
```

When importing a V1 multi-branch export, V2 requires you to specify the branch subfolder explicitly (V2's own exports write flat, with no subfolder at all, see [cm:stacks:export](#cmstacksexport)).

If you point V2 import at a V1 multi-branch export root, it attempts to read content files directly from the root (where only branches.json lives), finds nothing, and silently produces an empty import. See Import with CLI V2 Finds No Content in a CLI V1 Branch Export in the [CLI troubleshooting FAQs](/docs/headless-cms-cli-troubleshooting/faqs). Symptom: the command completes and reports success, and no content imports.

**Behavior Change: composable-studio Module Requires Basic Auth**

Same requirement as export. See [Authentication Changes](#authentication-changes) for the skip conditions, skip messages, and login command.

**Removed Import Config Keys (Custom Plugins and Config Files)**

If you maintain a custom plugin or tool that reads the import config object, V2 removes these keys:

Removed Key

Was Set To

importConfig.branchDir

a redundant alias for contentDir. V2 uses contentDir directly.

importConfig.contentVersion

a JS/TS module routing number used for internal module routing

Use importConfig.contentDir directly in V2.

**Rename:** modules\["asset-management"\] is now modules\["cs-assets"\]. If your external config JSON still uses the old key, V2 renames it internally and logs a deprecation warning.

**Fix:** Update your config files to use "cs-assets" directly to suppress the warning.

### cm:stacks:import-setup

**Removed Flags**

The cm:import-setup alias is removed, so use the full command name (see [Command Aliases Removed](#command-aliases-removed)). The removed short character is listed in [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx cm:import-setup --stack-api-key blt123 -B main
```

**After:**

```
csdx cm:stacks:import-setup --stack-api-key blt123 --branch main
```

### cm:stacks:bulk-entries

**Replaces (all removed in V2):** cm:entries:publish, cm:entries:publish-modified, cm:entries:publish-only-unpublished, cm:entries:publish-non-localized-fields, cm:entries:unpublish, cm:entries:update-and-publish, cm:stacks:publish (entries), cm:stacks:unpublish (entries), cm:stacks:publish-revert

V2 replaces all 15 commands in the @contentstack/cli-cm-bulk-publish plugin (across cm:entries:\*, cm:stacks:\*, cm:bulk-publish:\*, and cm:assets:\*) with 3 commands in @contentstack/cli-bulk-operations, each driven by an \--operation flag instead of a dedicated command per action. Rewrite every bulk publish script against the new flag-based interface.

**V1 to V2 Command Mapping**

V1 Command (REMOVED)

V2 Replacement

csdx cm:entries:publish

csdx cm:stacks:bulk-entries --operation publish

csdx cm:entries:publish-modified

csdx cm:stacks:bulk-entries --operation publish --filter modified

csdx cm:entries:publish-only-unpublished

csdx cm:stacks:bulk-entries --operation publish --filter unpublished

csdx cm:entries:publish-non-localized-fields

csdx cm:stacks:bulk-entries --operation publish --filter non-localized

csdx cm:entries:unpublish

csdx cm:stacks:bulk-entries --operation unpublish

csdx cm:entries:update-and-publish

csdx cm:stacks:bulk-entries --operation publish

csdx cm:stacks:publish (for entries)

csdx cm:stacks:bulk-entries --operation publish

csdx cm:stacks:unpublish (for entries)

csdx cm:stacks:bulk-entries --operation unpublish

csdx cm:bulk-publish:cross-publish

csdx cm:stacks:bulk-entries --operation publish --source-alias <alias>

csdx cm:stacks:publish-revert --log-file ./log.json

csdx cm:stacks:bulk-entries --revert ./log.json

csdx cm:stacks:publish-configure

**NO EQUIVALENT, REMOVED**

csdx cm:stacks:publish-clear-logs

**NO EQUIVALENT, REMOVED**

\--filter **valid values:** draft, modified, unpublished, non-localized. Passing any other value causes an immediate error.

```
csdx cm:stacks:bulk-entries --operation publish \
  --content-types blog article \
  --environments prod \
  --locales en-us \
  --stack-api-key bltXXX \
  --alias myalias

csdx cm:stacks:bulk-entries --operation unpublish \
  --content-types blog \
  --environments prod \
  --locales en-us \
  --stack-api-key bltXXX \
  --alias myalias

csdx cm:stacks:bulk-entries --revert ./log.json \
  --stack-api-key bltXXX \
  --alias myalias
```

**Cross-Publish Migration (cm:bulk-publish:cross-publish to \--source-alias)**

**Before:** V1 accepts an inline \--delivery-token flag.

**After:** V2 requires a stored delivery token alias. Complete this one-time setup:

1.  Store the delivery token as an alias.
2.  Use the alias in cm:stacks:bulk-entries.

```
csdx auth:tokens:add \
  -a staging-delivery \
  --delivery \
  --token bltABC \
  --stack-api-key blt123 \
  --environment staging

csdx cm:stacks:bulk-entries \
  --operation publish \
  --source-env staging \
  --source-alias staging-delivery \
  --content-types blog article \
  --environments prod \
  --locales en-us \
  -k blt123
```

**\--api-version Flag Removed**

V2 hardcodes api\_version: '3.2' on every publish and unpublish call. V2 removes the \--api-version flag. Passing it fails immediately:

```
ERROR: Nonexistent flag: --api-version
```

**Fix:** Remove \--api-version from all bulk publish scripts.

### cm:stacks:bulk-assets

**Replaces (all removed in V2):** cm:assets:publish, cm:assets:unpublish, cm:stacks:publish (assets), cm:stacks:unpublish (assets)

**V1 to V2 Command Mapping**

V1 Command (REMOVED)

V2 Replacement

csdx cm:assets:publish

csdx cm:stacks:bulk-assets --operation publish

csdx cm:assets:unpublish

csdx cm:stacks:bulk-assets --operation unpublish

```
csdx cm:stacks:bulk-assets --operation publish \
  --environments prod \
  --locales en-us \
  --stack-api-key bltXXX \
  --alias myalias
```

**New: CS Assets Bulk Delete and Move**

**No prior equivalent in V1.** V2 adds two new operation types to cm:stacks:bulk-assets that target the CS Assets API, separate from the CMS publish pipeline:

Operation

What it does

\--operation delete

Bulk delete assets from a CS Assets space (async job)

\--operation move

Bulk move assets to a target folder in a CS Assets space

**CS Assets bulk delete:**

```
csdx cm:stacks:bulk-assets \
  --operation delete \
  --space-uid am123 \
  --org-uid bltOrg \
  --locale en-us \
  --asset-uids-file ./assets.json
```

assets.json contains { "uids": \["uid1", "uid2"\] }.

**CS Assets bulk move:**

```
csdx cm:stacks:bulk-assets \
  --operation move \
  --space-uid am123 \
  --org-uid bltOrg \
  --target-folder-uid amFolder \
  --asset-uids-file ./assets.json
```

**Requirements:**

*   Configure csAssetsUrl in region settings first:
    
    ```
    csdx config:set:region --cs-assets <url>
    ```
    
*   Do not combine CMS flags (\--stack-api-key, \--alias, \--environments, \--locales, \--branch) with CS Assets flags.
    

Operation

\--locale

delete

Required

move

Not accepted

**Where to find \--space-uid and \--org-uid:**

1.  In the Contentstack UI, go to **Organization > Contentstack Assets > Settings**.
2.  Note the Space UID and Organization UID shown there.

V2 hardcodes api\_version: '3.2' on all calls (same as bulk-entries). V1 never had an \--api-version flag on this command.

### cm:stacks:bulk-taxonomies

V1 already has cm:stacks:bulk-taxonomies for bulk publishing or unpublishing taxonomy terms, with an \--api-version flag. V2 removes \--api-version and hardcodes api\_version: '3.2' on all calls.

Flag

Short Flag

Type

Required

Default

Description

\--operation

\-

string

No. Prompted if omitted

\-

publish or unpublish

\--stack-api-key

\-k

string

No. Prompted if \--alias is not used

\-

Stack API key

\--alias

\-a

string

No. Prompted if \--stack-api-key is not used

\-

Management token alias

\--environments

\-

string\[\]

No. Prompted if omitted

\-

Target environments (multiple allowed)

\--locales

\-

string\[\]

No. Prompted if omitted

\-

Target locales (multiple allowed)

\--taxonomies

\-

string

No. Acts on every taxonomy in the stack if omitted

\-

Comma-separated taxonomy UIDs. Omit to target all taxonomies.

\--branch

\-

string

No

main

Branch (defaults to main)

\--yes

\-y

boolean

No

false

Skip confirmation prompt

**Publish specific taxonomies:**

```
csdx cm:stacks:bulk-taxonomies \
  --operation publish \
  --environments staging prod \
  --locales en-us fr-fr \
  --taxonomies products_tax,brands_tax \
  --stack-api-key bltXXX \
  --alias myalias
```

**Publish all taxonomies:**

```
csdx cm:stacks:bulk-taxonomies \
  --operation publish \
  --environments prod \
  --locales en-us \
  --stack-api-key bltXXX \
  --alias myalias
```

### cm:stacks:seed

**Removed Flags**

The cm:seed alias is removed, so use the full command name (see [Command Aliases Removed](#command-aliases-removed)). Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx cm:seed -s blt123 -r contentstack/kickstart-stack-seed -o orgUid
```

**After:**

```
csdx cm:stacks:seed --stack-api-key blt123 --repo contentstack/kickstart-stack-seed
```

**Behavior Change: Curated List Replaces GitHub API in Interactive Mode**

**Before:** running csdx cm:stacks:seed without \--repo in V1 queries the GitHub API for all Contentstack repos.

**After:** V2 shows a fixed curated list of 3 repos:

1.  Kickstart stack seed (contentstack/kickstart-stack-seed)
2.  Kickstart Veda (contentstack/kickstart-veda-seed)
3.  Compass starter stack (contentstack/compass-starter-stack)

**Note:** V2 removes contentstack/stack-starter-app from the curated list. If you need it, pass it directly with \--repo contentstack/stack-starter-app.

If you need a repo that is not on this list, use \--repo owner/repo directly.

### cm:bootstrap

**Removed Flags**

\--appName and \--directory are renamed, and both renames are listed in [Type Mapping Reference](#type-mapping-reference). One further flag is removed outright:

Removed

V2 Replacement

\--appType / \-s

_(removed, no replacement needed, V2 hardcodes app type internally)_

**Note:** V1 has a short flag collision, both \--appName and \--alias claim \-a. V2 resolves this: \--app-name has no short character, and \-a exclusively means \--alias. Any script that used \-a for app name must switch to \--app-name (long form only).

**Before:**

```
csdx cm:bootstrap --appName reactjs --directory ./myapp --appType sampleapp
```

**After:**

```
csdx cm:bootstrap --app-name compass-app --project-dir ./myapp
```

**13 App Configs Removed**

V2 no longer accepts the following \--app-name values. Passing any of them throws CLI\_BOOTSTRAP\_INVALID\_APP\_NAME.

**Removed sample apps (4), were in the** sampleApps **interactive list:**

\--app-name

GitHub Source

Stack Seed

reactjs

contentstack/contentstack-reactjs-universal-sample-app

contentstack/stack-contentstack-reactjs-universal-sample-app

nextjs

contentstack/contentstack-nextjs-react-universal-demo

contentstack/stack-contentstack-nextjs-react-universal-demo

gatsby

contentstack/gatsby-starter-contentstack

contentstack/stack-gatsby-starter-contentstack

angular

contentstack/contentstack-angular-modularblock-example

contentstack/stack-contentstack-angular-modularblock-example

**Removed starter apps (8), were in the** starterApps **interactive list:**

\--app-name

GitHub Source

Stack Seed

reactjs-starter

contentstack/contentstack-react-starter-app

contentstack/stack-starter-app

nextjs-starter

contentstack/contentstack-nextjs-starter-app

contentstack/stack-starter-app

gatsby-starter

contentstack/contentstack-gatsby-starter-app

contentstack/stack-starter-app

angular-starter

contentstack/contentstack-angular-starter

contentstack/stack-starter-app

nuxt-starter

contentstack/contentstack-nuxtjs-starter-app

contentstack/stack-starter-app

vue-starter

contentstack/contentstack-vuejs-starter-app

contentstack/stack-starter-app

stencil-starter

contentstack/contentstack-stencil-starter-app

contentstack/stack-starter-app

nuxt3-starter

contentstack/contentstack-nuxt3-starter-app

contentstack/stack-starter-app

**Removed hidden config entry (1), never shown interactively, passable through** \--app-name**:**

\--app-name

GitHub Source

nuxtjs-disabled

contentstack/contentstack-nuxtjs-vue-universal-demo

**Valid App Names in V2 (8)**

These apps existed in V1's starterApps list and carry over to V2 unchanged. Display names ending in SSR or SSG name the app's rendering strategy, server-side rendering (SSR) or static site generation (SSG):

\--app-name

Display Name

GitHub Source

Stack Seed

compass-app

Compass App

contentstack/compass-starter-app

contentstack/compass-starter-stack

kickstart-next

Kickstart Next.js

contentstack/kickstart-next

contentstack/kickstart-stack-seed

kickstart-next-ssr

Kickstart Next.js SSR

contentstack/kickstart-next-ssr

contentstack/kickstart-stack-seed

kickstart-next-ssg

Kickstart Next.js SSG

contentstack/kickstart-next-ssg

contentstack/kickstart-stack-seed

kickstart-next-graphql

Kickstart Next.js GraphQL

contentstack/kickstart-next-graphql

contentstack/kickstart-stack-seed

kickstart-next-middleware

Kickstart Next.js Middleware

contentstack/kickstart-next-middleware

contentstack/kickstart-stack-seed

kickstart-nuxt

Kickstart NuxtJS

contentstack/kickstart-nuxt

contentstack/kickstart-stack-seed

kickstart-nuxt-ssr

Kickstart NuxtJS SSR

contentstack/kickstart-nuxt-ssr

contentstack/kickstart-stack-seed

### cm:stacks:audit

**Removed Flags**

V2 strips the short aliases from both commands. See [Command Aliases Removed](#command-aliases-removed) for the full alias list.

**Before:**

```
csdx audit
csdx audit:fix
```

**After:**

```
csdx cm:stacks:audit
csdx cm:stacks:audit:fix
```

**Behavior Change: Audit Reads Per-UID Files, So V1 Exports Produce Empty Results**

cm:stacks:audit now uses readContentTypeSchemas and readGlobalFieldSchemas (the same utilities V2 import uses) to load content type and global field schemas from the \--report-path directory. These utilities read individual <uid>.json files and explicitly ignore schema.json and globalfields.json.

Running audit against a V1 export directory has the same per-module impact as V2 import:

Module

V1 export writes

Impact on audit

Content types

Individual <uid>.json files

**No impact**, content types load correctly

Global fields

globalfields.json only (no individual files)

**False clean**, audit returns zero results

**Migration:** Re-export global fields with V2 before auditing. Do not run cm:stacks:audit:fix on a V1 export, because it removes Global field fields from your content types. If you cannot re-export, audit the V1 export with CLI V1.

See Audit with CLI V2 Reports No Global Field Issues in a CLI V1 Export in the [CLI troubleshooting FAQs](/docs/headless-cms-cli-troubleshooting/faqs). Symptom: audit reports zero global-field issues even when the export contains actual issues.

### cm:stacks:migration

**Removed Flags**

Removed

V2 Replacement

\-B

\--branch

\-A

\--alias

\-n

\--file-path

\--api-key

\--stack-api-key

\--authtoken

_(removed, use_ csdx auth:login _then_ \--alias_)_

\--management-token-alias

\--alias

\--filePath

\--file-path

\--multi

\--multiple

**Before:**

```
csdx cm:migration -B feature-branch -n ./migrate.js
```

**After:**

```
csdx cm:stacks:migration --branch feature-branch --file-path ./migrate.js
```

**Taxonomy Migration Script Removed**

V2 deprecates taxonomy migration through cm:stacks:migration and does not include the sample import-taxonomies.js script. The [Taxonomy Migration](/docs/headless-cms/cli-taxonomy-migration) steps work with V1 only. In V2, use [cm:stacks:export](#cmstacksexport) and [cm:stacks:import](#cmstacksimport) to migrate taxonomies between stacks.

### cm:stacks:validate-regex

**Removed Flags**

Every removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference). The long-form flag names are unchanged.

**Before:**

```
csdx cm:stacks:validate-regex -c -g -f ./output
```

**After:**

```
csdx cm:stacks:validate-regex --contentType --globalField --filePath ./output
```

**Output Format**

The results table and results.csv file use the same column order in both V1 and V2: Module, Title, UID, Invalid Regex Count. If you parse CSV output by header name, you need no changes.

### auth:tokens

In V2, auth:tokens no longer lists tokens directly. It becomes a help dispatcher for its sub-commands.

**Before:** csdx auth:tokens lists your tokens in V1.

```
csdx auth:tokens
```

**After:** V2 displays sub-command help instead. Use csdx auth:tokens:list to list tokens.

```
csdx auth:tokens:list
```

**Silent failure risk:**

*   **V1:** csdx auth:tokens prints a token table to stdout.
*   **V2:** csdx auth:tokens prints help text to stdout instead, with no error code. A script that parses this output for a token table silently receives help text instead.

**Short alias removed:**

*   **V1:** csdx tokens is a short alias for csdx auth:tokens.
*   **V2:** removes the alias. csdx tokens fails with "command not found".

### auth:tokens:add

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference). Three of them were hidden flags in V1: \--api-key is replaced by \--stack-api-key, \-f / \--force becomes \-y / \--yes, and \--branch is removed entirely with no replacement.

**Before:**

```
csdx auth:tokens:add -a myalias -d -t bltABC -k blt123
```

**After:**

```
csdx auth:tokens:add -a myalias --delivery --token bltABC --stack-api-key blt123
```

### auth:tokens:remove

**Removed Flags**

\-i / \--ignore is removed, as listed in [Type Mapping Reference](#type-mapping-reference).

**Before:** in V1, \-i / \--ignore makes the command succeed silently even if the alias does not exist.

```
csdx auth:tokens:remove -a myalias -i
```

**After:** V2 removes the flag entirely.

*   **V1 (without \-i):** if the alias does not exist, the command exits non-zero.
*   **V1 (with \-i):** the command always exits 0, even if the alias does not exist.
*   **V2:** always behaves like V1's \-i case. If the alias does not exist, it prints a yellow warning and exits 0, regardless of any flag.

```
csdx auth:tokens:remove -a myalias
```

V2 prints No token found with alias 'myalias'. (yellow) and exits 0. Scripts that relied on a non-zero exit when the alias was missing (V1's no-flag default) must account for this change.

### auth:logout

**Removed Flags**

\-f / \--force (a hidden flag in V1) is removed, as listed in [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx auth:logout -f
csdx auth:logout --force
```

**After:** V2 returns an "Unexpected argument" error for both forms above. Use:

```
csdx auth:logout -y
csdx auth:logout --yes
```

### config:set:region

**Removed Flags**

Every removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference). The long-form flag names are unchanged.

**Before:**

```
csdx config:set:region -d https://cdn.example.com -m https://api.example.com --ui-host https://app.example.com -n MyRegion
```

**After:**

```
csdx config:set:region --cda https://cdn.example.com --cma https://api.example.com --ui-host https://app.example.com --name MyRegion
```

**New: \--cs-assets Flag**

**No prior equivalent in V1.** V2 adds a \--cs-assets flag for specifying the Contentstack Assets API URL when you configure a custom region:

```
csdx config:set:region \
  --cma https://custom.cma.example.com \
  --cda https://custom.cda.example.com \
  --ui-host https://custom.ui.example.com \
  --name MyRegion \
  --cs-assets https://custom.am-api.example.com
```

When you omit \--cs-assets, V2 derives the CS Assets URL from the Content Management API (CMA) URL automatically.

config:get:region now also shows Contentstack Assets URL in its output.

### config:set:log

V2 stores the console log preference under a different config key, so your V1 setting does not carry over. V1 stores it as log\["show-console-logs"\] (hyphenated). V2 stores it as log\["showConsoleLogs"\] (camelCase). The two formats are not compatible.

**After you upgrade, V2 silently ignores your V1 console log configuration.** Progress bars are the default. If your CI needs console log output, re-run:

```
csdx config:set:log --show-console-logs
```

To explicitly switch back to progress bars (the V2 default):

```
csdx config:set:log --no-show-console-logs
```

See Console Log Setting from CLI V1 Has No Effect After Upgrading to CLI V2 in the [CLI troubleshooting FAQs](/docs/headless-cms-cli-troubleshooting/faqs). Symptom: info and success log lines no longer appear in the console, even though you configured console logs under V1.

### config:set:early-access-header

**Documentation fix, no behavioral change.**

V1 has the \--header and \--header-alias descriptions swapped:

Flag

V1 description (incorrect)

V2 description (correct)

\--header-alias

"Provide the Early Access header value"

"Provide a name (alias) for this Early Access header"

\--header

"Provide the Early Access header alias name"

"Provide the Early Access header value"

The actual behavior was always: \--header-alias sets the alias name, \--header sets the header value. If you followed V1's incorrect help text and passed values in the wrong order, correct your scripts:

```
csdx config:set:early-access-header --header-alias myheader --header x-header-value
```

### tsgen

tsgen generates TypeScript interfaces from your stack's content type schemas, authenticated with a delivery token alias. Use the generated types to annotate content model access in a TypeScript client, whether that client uses the Contentstack Delivery SDK or a plain HTTP request. See the [tsgen plugin docs](/docs/headless-cms/cli-tsgen-plugin) for full usage.

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference).

\-a (short for alias) is kept, on the renamed \--alias flag.

**Before:**

```
csdx tsgen --token-alias myalias -o ./types -p CS_ -d
```

**After:**

```
csdx tsgen --alias myalias --output ./types --prefix CS_ --doc
```

Or use \-a for alias:

```
csdx tsgen -a myalias --output ./types --prefix CS_ --doc
```

### app:create

**Removed Flags**

\-n is removed. Use \--name (long form only). See [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx app:create -n my-app
```

**After:**

```
csdx app:create --name my-app
```

### migrate:convert

**Removed Flags**

Every removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference). The long-form flag names are unchanged.

**Before:**

```
csdx migrate:convert -o ./output -m en-us -a v2_
```

**After:**

```
csdx migrate:convert --output ./output --master-locale en-us --affix v2_
```

### migrate:export

**Removed Flags**

\-o is removed. Use \--output (long form only). See [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx migrate:export -o ./output
```

**After:**

```
csdx migrate:export --output ./output
```

### content-type:audit

**Note:** the content-type:\* commands belong to a separate plugin (contentstack-cli-content-type) that inspects and compares content type schemas. They differ from cm:stacks:\* commands: they do not export or import content, they analyze schema structure. The flag changes below apply to every command in this namespace.

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx content-type:audit --stack blt123 --token-alias myalias -c blog
```

**After:**

```
csdx content-type:audit --alias myalias --content-type blog
```

### content-type:compare

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx content-type:compare --stack blt123 --token-alias myalias -c blog -l v1 -r v2
```

**After:**

```
csdx content-type:compare --alias myalias --content-type blog --left v1 --right v2
```

### content-type:compare-remote

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference).

Note: content-type:compare-remote never has \--stack / \--token-alias flags in V1.

**Before:**

```
csdx content-type:compare-remote -o bltOrigin -r bltRemote -c blog
```

**After:**

```
csdx content-type:compare-remote --origin-stack bltOrigin --remote-stack bltRemote --content-type blog
```

### content-type:details

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx content-type:details --stack blt123 --token-alias myalias -c blog -p
```

**After:**

```
csdx content-type:details --alias myalias --content-type blog --path
```

### content-type:diagram

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx content-type:diagram --stack blt123 --token-alias myalias -o ./diagram.svg -d landscape -t svg
```

**After:**

```
csdx content-type:diagram --alias myalias --output ./diagram.svg --direction landscape --type svg
```

### content-type:list

**Removed Flags**

Every flag rename and removed short character for this command is listed in [Type Mapping Reference](#type-mapping-reference).

**Before:**

```
csdx content-type:list --stack blt123 --token-alias myalias -o title
```

**After:**

```
csdx content-type:list --alias myalias --order title
```

## CS Assets (Asset Management 2.0)

**No prior equivalent in V1.** V2 adds support for Contentstack's CS Assets system (Asset Management 2.0, or AM 2.0) in export, import, and import-setup, each of which detects and handles CS Assets automatically if your stack has linked workspaces.

**Bulk operations support:** delete and move only. CS Assets has no bulk publish or unpublish support.

**Export:** if your stack has linked workspaces configured in Contentstack Assets settings, export writes CS Assets data to a spaces/ directory alongside the standard assets/ directory. If your stack has no linked workspaces, export falls back to standard asset export automatically:

```
export/
  assets/         (CMS assets, unchanged)
  spaces/         (new: CS Assets)
    <space-id>/workspaces/
    <space-id>/asset_types/
    <space-id>/assets/
    <space-id>/folders/
```

**Import:** V2 detects the spaces/ directory and imports CS Assets automatically.

**Import-setup:** V2 detects CS Assets exports and generates identity UID and URL mapper files.

**New bulk operations:** cm:stacks:bulk-assets --operation delete and \--operation move handle CS Assets (see the new flags \--space-uid, \--org-uid, \--workspace, \--asset-uids-file, \--target-folder-uid in [cm:stacks:bulk-assets](#cmstacksbulk-assets)).

## Taxonomy Publishing

V2 adds taxonomy publishing support across export, import, and bulk operations.

**Before:** V1 export does not capture taxonomy publish details. V1 import does not re-publish taxonomies.

**After:**

*   **Export** captures publish\_details per locale for each taxonomy.
*   **Import** re-publishes taxonomies after import by default. To skip publishing (for example, if you want to review taxonomies before publishing):
    
    ```
    csdx cm:stacks:import --skip-taxonomy-publish -d ./export -k bltXXX
    ```
    
*   cm:stacks:bulk-taxonomies handles bulk taxonomy publish operations (see [cm:stacks:bulk-taxonomies](#cmstacksbulk-taxonomies)).

## Pre-Upgrade Checklist

This checklist orders items by risk. Complete top sections before lower ones.

### Critical: Do These First

1.  Test the entire upgrade in a non-production environment before touching production.
2.  **Your saved tokens carry over automatically.** Management tokens stored with csdx auth:tokens:add are available immediately after upgrading. You need no re-authentication. ([Tokens and Config Carry Over Automatically](#tokens-and-config-carry-over-automatically))

### High-Risk Script Changes

1.  Add an explicit \--branch flag to **all** cm:stacks:export calls for non-main branches. V2 only exports main when you omit \--branch. ([cm:stacks:export](#cmstacksexport), Branch Export Silently Overwrites Another Branch's Data)
2.  Use a **separate** \--data-dir **per branch.** V2 output is always flat (no <branch-uid>/ subfolder), so exporting two branches to the same directory overwrites the first, with only a warning. (Branch Export Silently Overwrites Another Branch's Data)
3.  Rewrite all cm:entries:publish\*, cm:assets:publish\*, cm:bulk-publish:\*, cm:stacks:publish, cm:stacks:unpublish calls to cm:stacks:bulk-entries / cm:stacks:bulk-assets commands. ([cm:stacks:bulk-entries](#cmstacksbulk-entries), [cm:stacks:bulk-assets](#cmstacksbulk-assets))
4.  Verify publish behavior in a staging stack. All bulk publish and unpublish calls now use api\_version: '3.2', and V2 removes the \--api-version flag. ([All Publish Operations Now Use NRP](#all-publish-operations-now-use-nrp))
5.  Remove checks for export-info.json or content\_types/schema.json in post-export tooling. V2 does not write these files. ([cm:stacks:export](#cmstacksexport))
6.  Update tooling that reads global\_fields/globalfields.json to iterate per-UID JSON files instead. ([Global Fields Format Changed (Per-File)](#cmstacksexport))
7.  Replace any cm:stacks:migration call that runs the sample import-taxonomies.js script. V2 does not include the script. ([cm:stacks:migration](#cmstacksmigration))

### CI and Pipeline Audit

1.  Verify your CI does not parse stdout for success signals. The output format changed to progress bars by default. ([Default Output: Progress Bars Replace Console Logs](#default-output-progress-bars-replace-console-logs))
2.  Run csdx config:set:log --show-console-logs after upgrading if your CI parses console output. V2 silently drops the V1 log setting. (V1 Console Log Config Silently Ignored After Upgrade)

### Script Audit: Command Renames

1.  Replace csdx cm:export with csdx cm:stacks:export. ([Command Aliases Removed](#command-aliases-removed))
2.  Replace csdx cm:import with csdx cm:stacks:import. ([Command Aliases Removed](#command-aliases-removed))
3.  Replace csdx cm:import-setup with csdx cm:stacks:import-setup. ([Command Aliases Removed](#command-aliases-removed))
4.  Replace csdx cm:seed with csdx cm:stacks:seed. ([Command Aliases Removed](#command-aliases-removed))
5.  Replace csdx tokens with csdx auth:tokens:list. ([Command Aliases Removed](#command-aliases-removed))
6.  Replace csdx auth:tokens (when used to list tokens) with csdx auth:tokens:list. ([auth:tokens](#authtokens))
7.  Replace csdx audit with csdx cm:stacks:audit. ([Command Aliases Removed](#command-aliases-removed))

### Script Audit: Flag Changes

1.  Remove \--stack-uid / \-s everywhere and use \--stack-api-key instead. ([Type Mapping Reference](#type-mapping-reference))
2.  Remove \--data and use \--data-dir instead. ([Type Mapping Reference](#type-mapping-reference))
3.  Remove \--management-token-alias and use \--alias instead. ([Type Mapping Reference](#type-mapping-reference))
4.  Remove \--auth-token / \-A and use csdx auth:login then \--alias instead. ([Type Mapping Reference](#type-mapping-reference))
5.  Remove \--skip-app-recreation from all import scripts. V2 has no replacement. ([cm:stacks:import](#cmstacksimport))
6.  Remove \--token-alias on tsgen and use \--alias instead. ([tsgen](#tsgen))
7.  Audit scripts for removed short flags on export and import commands: \-m / \-t / \-B / \-b / \-A (switch to long form only). ([cm:stacks:export](#cmstacksexport), [cm:stacks:import](#cmstacksimport))
8.  Update cm:bootstrap flags: \--appName to \--app-name, \--directory to \--project-dir. ([cm:bootstrap](#cmbootstrap))
9.  Remove bootstrap app names that no longer exist: reactjs, nextjs, gatsby, angular, and the \*-starter variants. ([cm:bootstrap](#cmbootstrap))
10.  Update content-type:\* commands: remove \--stack / \-s, \--token-alias / \-a, and every listed short character. ([content-type:audit](#content-typeaudit))
11.  Replace csdx auth:logout -f / \--force with csdx auth:logout -y / \--yes. ([auth:logout](#authlogout))

### Plugin Management

1.  Install the launch plugin separately if you use launch:\* commands: csdx plugins:install @contentstack/cli-launch. ([launch Plugin: Now Opt-In](#launch-plugin-now-opt-in))
2.  Install the migrate-rte plugin separately if you use cm:entries:migrate-html-rte: csdx plugins:install @contentstack/cli-cm-migrate-rte. ([migrate-rte Plugin: Now Opt-In](#migrate-rte-plugin-now-opt-in))
3.  If you use CS Assets, verify your stack has linked workspaces configured in Contentstack Assets settings. Otherwise export falls back to standard asset export. ([CS Assets (Asset Management 2.0)](#cs-assets-asset-management-20))

### Custom Plugins (Plugin Authors Only)

1.  Update engines.node to \>=22.0.0 in your plugin's package.json. ([Node.js 22+](#nodejs-22))
2.  Update @oclif/core from ^3.0.0 to ^4.11.14.
3.  Add @contentstack/cli-command and @contentstack/cli-utilities at ~2.0.0 to your dependencies. Import Command from @contentstack/cli-command, and flags and Args from @contentstack/cli-utilities, so your plugin needs no direct dependency on @oclif/core.
4.  Point oclif.commands at ./lib/commands, the compiled JavaScript output, rather than ./src/commands. A build step is now required before linking or installing, and pointing at TypeScript source makes command discovery fail.
5.  Rewrite your tests if you use @oclif/test. Version 4 removed the chained test.stdout().command().it() API entirely and now exports only runCommand, captureOutput and runHook. The old API throws TypeError: Cannot read properties of undefined.

For the full authoring workflow, see [Create Custom CLI Plugins for Contentstack](/docs/headless-cms/create-custom-cli-plugins).

### Test Run

1.  Run a full export and import cycle on a non-production stack before cutting over.
2.  Verify branch exports capture the correct branches explicitly.
3.  If you use CS Assets, verify your stack has linked workspaces configured. Otherwise export falls back to standard asset export automatically, with no error.
4.  If you use bulk publish or unpublish, run a test publish in staging. All calls now use api\_version: '3.2'.

## Next Steps

*   [Contentstack CLI documentation](/docs/headless-cms/install-the-cli): reference documentation for the V2 CLI.
*   [Create Custom CLI Plugins for Contentstack](/docs/headless-cms/create-custom-cli-plugins): the V2 plugin authoring guide, updated for @oclif/core v4.
*   [Migrate content from HTML RTE to JSON RTE](/docs/headless-cms/cli-migrate-content-from-html-rte-to-json-rte): docs for the migrate-rte plugin you now install separately (see [migrate-rte Plugin: Now Opt-In](#migrate-rte-plugin-now-opt-in)).
*   [tsgen plugin docs](/docs/headless-cms/cli-tsgen-plugin): full usage reference for the tsgen command (see [tsgen](#tsgen)).