Bulk Operations in CLI
Overview
The CLI Bulk Operations plugin streamlines content management workflows by providing robust commands for bulk publishing and unpublishing operations. It intelligently handles API rate limits, retries failed operations, and processes large volumes of content efficiently.
What Problem Does It Solve?
When managing content at scale in Contentstack, you often need to:
- Publish hundreds or thousands of entries to multiple environments
- Unpublish outdated content across multiple locales
- Handle API rate limits gracefully without manual intervention
- Retry failed operations automatically
- Track operation progress and results
This plugin handles all of these challenges automatically.
Prerequisites
- Node.js >= 22
- Contentstack CLI installed
- Valid Contentstack account with Management Token or API Key
Install Plugin
# Install Contentstack CLI npm install -g @contentstack/cli # Verify installation csdx cm:stacks:bulk-entries --help
Installation
Commands
Bulk Entries
Perform bulk operations on entries with advanced filtering and publishing options.
Syntax
csdx cm:stacks:bulk-entries [OPTIONS]
Required Options
| Flag | Short Flag | Type | Required | Default | Description |
|---|---|---|---|---|---|
| --operation | - | string | No. Prompted if omitted | - | Operation type: publish or unpublish. Example: --operation publish |
| --environments | - | string[] | No. Prompted if omitted | - | The name of the environment(s) on which entries/assets will be published. In case of multiple environments, specify their names separated by spaces. Example: --environments prod staging |
| --locales | - | string[] | No. Prompted if omitted | - | Locales in which entries/assets will be published. In case of multiple locales, specify the codes separated by spaces. Example: --locales en-us fr-fr |
| --stack-api-key | -k | string | No. Prompted if --alias is not used | - | API key of the source stack. You must use either the --stack-api-key flag or the --alias flag. Example: -k blt********* |
| --alias | -a | string | No. Prompted if --stack-api-key is not used | - | Alias (name) of the management token. You must use either the --alias flag or the --stack-api-key flag. Example: -a my-token |
Entry-Specific Options
| Flag | Short Flag | Type | Required | Default | Description |
|---|---|---|---|---|---|
| --content-types | - | string[] | No | - | Content type UIDs to perform operation on. If not provided, operates on all content types. |
| --filter | - | string | No | - | Filter entries by status: draft, modified, unpublished, non-localized |
| --include-variants | - | boolean | No | false | Includes entry variants (alternate versions of a base entry) in the bulk operation. By default, only base entries are processed. |
Filter values:
- draft: Entries that have never been published
- modified: Entries updated since the last publish
- unpublished: Entries that are not published to the target environment (the first environment you pass to --environments), including entries never published anywhere
- non-localized: Entries where non-localized fields have been updated in the master locale, requiring localized entries to be republished
General Options
| Flag | Short Flag | Type | Required | Default | Description |
|---|---|---|---|---|---|
| --publish-mode | - | string | No | bulk | Publish mode: bulk (uses Bulk Publish API) or single (individual API calls) |
| --branch | - | string | No | main | The name of the branch where you want to perform the bulk publish operation. If you don't mention the branch name, then by default the content from main branch will be published. |
| --source-env | - | string | No | - | Source environment for cross-publish |
| --source-alias | - | string | No | - | Alias name for source environment delivery token (required for cross-publish). Add delivery token using: csdx auth:tokens:add |
| --yes | -y | boolean | No | false | Set it to true to process the command with the current configuration. |
| --config | -c | string | No | - | The path of an optional configuration JSON file. The CLI accepts this flag, but it does not read the file in this release. Pass each option as a flag instead. |
| --retry-failed | - | string | No | - | Use this option to retry publishing the failed entries/assets from the logfile. |
| --revert | - | string | No | - | Revert publish operations from a log folder. |
| --bulk-operation-file | - | string | No | bulk-operation | Folder path to store operation logs. |
Examples
1. Publish all content types to production
csdx cm:stacks:bulk-entries \ --operation publish \ --environments production \ --locales en-us \ -k blt*******
2. Publish specific content types to multiple environments
csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post,article,page \ --environments dev,staging,production \ --locales en-us,es-es \ -k blt*******
3. Publish entries with non-localized field changes
csdx cm:stacks:bulk-entries \ --operation publish \ --filter non-localized \ --content-types blog_post \ --environments production \ -k blt*******
3. Publish only draft entries
csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post \ --filter draft \ --environments production \ --locales en-us \ -k blt*******
4. Cross-publish from production to staging
First, add the delivery token for the source environment (one-time setup):
# Add delivery token for production environment csdx auth:tokens:add \ -a prod-delivery \ --delivery \ --token prod-delivery-token \ --stack-api-key blt******* \ --environment production
Then use it for cross-publish:
csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post \ --source-env production \ --source-alias prod-delivery \ --environments staging \ --locales en-us \ -k blt*******
5. Publish using single mode for fine control
csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post \ --publish-mode single \ --environments production \ --locales en-us \ -k blt*******
6. Unpublish entries
csdx cm:stacks:bulk-entries \ --operation unpublish \ --content-types blog_post \ --environments staging \ --locales en-us \ -k blt*******
7. Retry failed operations
# Retry failed entries from a previous operation csdx cm:stacks:bulk-entries \ --retry-failed ./bulk-operation
8. Revert a publish operation
# Revert (unpublish) previously published entries csdx cm:stacks:bulk-entries \ --revert ./bulk-operation
9. Publish with entry variants
# Publish entries including their variants csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post \ --include-variants \ --environments production \ --locales en-us \ -k blt*******
Bulk Assets
Perform bulk operations on assets with folder and file type filtering.
Syntax
csdx cm:stacks:bulk-assets [OPTIONS]
Required Options
Same as bulk entries (see above).
Asset-Specific Options
| Flag | Short Flag | Type | Required | Default | Description |
|---|---|---|---|---|---|
| --folder-uid | - | string | No | - | The UID of the Assets' folder from which the assets need to be published. Default: cs_root. Example: --folder-uid cs_root |
| --backup-dir | - | string | No | - | Path to the import backup directory. Publishes each imported asset only to the environments and locales it was published to in the source stack, and skips assets that asset scanning has not cleared. Cannot be used with --environments, --locales, --folder-uid or --source-env. Example: --backup-dir ./_backup_123 |
| --dry-run | - | boolean | No | false | Shows the publish plan for --backup-dir without publishing any assets. Has no effect without --backup-dir. |
Examples
1. Publish all assets
csdx cm:stacks:bulk-assets \ --operation publish \ --environments production \ --locales en-us \ -k blt*******
2. Publish assets from specific folder
csdx cm:stacks:bulk-assets \ --operation publish \ --folder-uid cs_product_images \ --environments production \ --locales en-us \ -k blt*******
3. Cross-publish assets from production to staging
csdx cm:stacks:bulk-assets \ --operation publish \ --source-env production \ --source-alias prod-delivery \ --environments staging \ --locales en-us \ -k blt*******
Note: See Example 4 in Bulk Entries section for how to set up the delivery token alias.
4. Unpublish assets
csdx cm:stacks:bulk-assets \ --operation unpublish \ --environments staging \ --locales en-us \ -k blt*******
5. Retry failed asset operations
# Retry failed assets from a previous operation csdx cm:stacks:bulk-assets \ --retry-failed ./bulk-operation
6. Revert an asset publish operation
# Revert (unpublish) previously published assets csdx cm:stacks:bulk-assets \ --revert ./bulk-operation
Bulk CS Assets operations
Perform bulk delete or move operations on assets stored in cs-assets spaces. This command uses the cs-assets REST API and is separate from the CMA-based Bulk Publish API used by bulk-entries and bulk-assets.
Prerequisite: Your region must have CS Assets enabled. See Configure Regions.
Warning Do not combine CMS flags (--stack-api-key, --alias, --environments, --locales, --branch) with the CS Assets flags in the table below. The delete and move operations target the CS Assets API, not the CMS publish pipeline.
Syntax
csdx cm:stacks:bulk-assets [OPTIONS]
Options
| Flag | Short Flag | Type | Required | Default | Description |
|---|---|---|---|---|---|
| --operation | - | string | Yes, unless --retry-failed or --revert is used. Prompted if omitted | - | Operation type: delete or move |
| --space-uid | - | string | Yes, for delete and move. Prompted if omitted | - | UID of the CS Assets space |
| --org-uid | - | string | Yes, for delete and move. Prompted if omitted | - | Organization UID |
| --asset-uids-file | - | string | Yes, for delete and move. Prompted if omitted | - | Path to a JSON file listing the assets to act on, in the form { "uids": ["uid1", "uid2"] } |
| --workspace | - | string | No | main | Workspace to operate in. Default: main |
| --locale | - | string | Yes, for delete. Prompted if omitted | - | Locale to delete assets in. Required for delete and not accepted for move |
| --target-folder-uid | - | string | Yes, for move. Prompted if omitted | - | UID of the destination folder (move only) |
| --folder-uid | - | string | No | - | UID of the source folder to filter assets |
| --yes | -y | boolean | No | false | Skip confirmation prompt |
Examples
Bulk delete assets in a space:
csdx cm:stacks:bulk-assets \ --operation delete \ --space-uid blt1234567890abcdef \ --org-uid bltorg1234567890 \ --locale en-us \ --asset-uids-file ./assets.json
Bulk move assets to a different folder:
csdx cm:stacks:bulk-assets \ --operation move \ --space-uid blt1234567890abcdef \ --org-uid bltorg1234567890 \ --folder-uid cs_source_folder \ --target-folder-uid cs_destination_folder \ --asset-uids-file ./assets.json \ --yes
Bulk Taxonomies
Bulk publish or unpublish taxonomy terms. This command has no equivalent in CLI V1.
Syntax
csdx cm:stacks:bulk-taxonomies [OPTIONS]
Options
| Flag | Short Flag | Type | Required | Default | Description |
|---|---|---|---|---|---|
| --operation | - | string | No. Prompted if omitted | - | Operation type: publish or unpublish |
| --taxonomies | - | string | No. Acts on every taxonomy in the stack if omitted | - | UIDs of the taxonomies to act on. Separate multiple UIDs with a space. |
| --environments | - | string[] | No. Prompted if omitted | - | Environments to publish to or unpublish from |
| --locales | - | string[] | No. Prompted if omitted | - | Locales to act on |
| --stack-api-key | -k | string | No. Prompted if --alias is not used | - | API key of the target stack |
| --alias | -a | string | No. Prompted if --stack-api-key is not used | - | Management token alias of the target stack |
| --yes | -y | boolean | No | false | Skip confirmation prompt |
Examples
Publish taxonomy terms to an environment:
csdx cm:stacks:bulk-taxonomies \ --operation publish \ --taxonomies product_category \ --environments production \ --locales en-us \ --stack-api-key bltxxxxxx
Unpublish taxonomy terms:
csdx cm:stacks:bulk-taxonomies \ --operation unpublish \ --taxonomies product_category,region \ --environments production \ --locales en-us \ --alias myalias
Operation Modes
In both modes, every publish and unpublish request that the bulk commands send uses API version 3.2 (Nested Reference Publishing). The --api-version flag from CLI 1.x is removed, and the commands do not accept it. For details, see All Publish Operations Now Use NRP.
Bulk Mode (Default)
Uses Contentstack's native Bulk Publish APIs.
Best For:
- Publishing 100+ entries/assets
- Multi-environment deployments
Example:
csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post \ --environments production \ --locales en-us \ -k blt*******
Single Mode
Makes individual API calls for each item with intelligent rate limiting.
Best For:
- Small batches (less than 50 items)
- Operations requiring detailed error tracking
- Testing and debugging
Example:
csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post \ --environments production \ --locales en-us \ --publish-mode single \ -k blt*******
Cross-Publish Setup
Cross-publish allows you to promote content from one environment to another (e.g., staging → production). To use cross-publish, you need to set up a delivery token for the source environment.
Why Delivery Tokens?
Cross-publish uses the Delivery API to fetch only published content from the source environment. This ensures you're promoting exactly what's live, not draft content.
Setting Up Delivery Tokens
Step 1: Create a Delivery Token in Contentstack
- Navigate to Settings → Tokens → Delivery Tokens in your Contentstack stack
- Click + Add Delivery Token
- Name your token (e.g., "Production Delivery Token")
- Select the source environment (e.g., "production")
- Copy the generated delivery token
Step 2: Add Token to CLI
csdx auth:tokens:add \ -a <alias-name> \ --delivery \ --token <your-delivery-token> \ --stack-api-key <your-stack-api-key> \ --environment <source-environment>
Example:
# Add production delivery token csdx auth:tokens:add \ -a prod-delivery \ --delivery \ --token prod-delivery-token \ --stack-api-key blt******** \ --environment production # Add staging delivery token csdx auth:tokens:add \ -a staging-delivery \ --delivery \ --token stag-delivery-token \ --stack-api-key blt******** \ --environment staging
Step 3: Use in Cross-Publish Operations
# Promote from staging to production csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post \ --source-env staging \ --source-alias staging-delivery \ --environments production \ --locales en-us \ -k blt********
Managing Delivery Tokens
# List all stored tokens (including delivery tokens) csdx auth:tokens:list # Remove a delivery token csdx auth:tokens:remove -a staging-delivery
Use Cases
Use Case 1: Content Unpublish
Scenario: A critical bug is discovered in 500 blog posts that need immediate unpublishing from production.
Solution:
csdx cm:stacks:bulk-entries \ --operation unpublish \ --content-types blog_post \ --environments production \ --locales en-us,es-es,fr-fr \ --yes \ -k blt********
Result: All 500 blog posts unpublished across 3 locales in ~2 minutes (bulk mode).
Use Case 2: Scheduled Content Release
Scenario: Publish 200 product entries to production every Monday at 9 AM.
Solution: Create a cron job with a config file
# config.json
{
"operation": "publish",
"contentTypes": ["product"],
"environments": ["production"],
"locales": ["en-us"],
"filter": "modified",
"publishMode": "bulk"
}
# Cron command
0 9 * * 1 csdx cm:stacks:bulk-entries -c /path/to/config.json -k $STACK_API_KEY --yesUse Case 3: Cross-Environment Promotion
Scenario: Promote all content published in staging to production.
Setup (one-time):
# Add delivery token for staging environment csdx auth:tokens:add \ -a staging-delivery \ --delivery \ --token blt_staging_token \ --stack-api-key blt******** \ --environment staging
Solution:
# Promote entries csdx cm:stacks:bulk-entries \ --operation publish \ --source-env staging \ --source-alias staging-delivery \ --environments production \ --locales en-us \ -k blt******** # Promote assets csdx cm:stacks:bulk-assets \ --operation publish \ --source-env staging \ --source-alias staging-delivery \ --environments production \ --locales en-us \ -k blt********
Result: All staging content promoted to production with verification.
How it works: The --source-alias uses a stored delivery token to fetch only published content from the source environment. This ensures you're promoting exactly what's live in staging.
Use Case 4: Selective Publishing with Filters
Scenario: Publish only draft entries that have never been published.
Solution:
csdx cm:stacks:bulk-entries \ --operation publish \ --content-types article,blog_post \ --filter draft \ --environments production \ --locales en-us \ -k blt********
Result: Only unpublished entries are sent to production, saving API calls.
Use Case 5: Multi-Locale Product Launch
Scenario: Launch 50 new product entries across 10 locales and 3 environments simultaneously.
Solution:
csdx cm:stacks:bulk-entries \ --operation publish \ --content-types product \ --environments dev,staging,production \ --locales en-us,es-es,fr-fr,de-de,it-it,pt-br,ja-jp,zh-cn,ko-kr,ar-ae \ --publish-mode bulk \ -k blt********
Result: 50 products × 10 locales × 3 envs = 1,500 publish operations completed in ~5 minutes via batching.
Use Case 6: Retry Failed Operations
Scenario: A network issue caused 20 out of 200 entries to fail publishing.
Solution:
# Retry only failed entries csdx cm:stacks:bulk-entries \ --retry-failed bulk-operation/failed-20250112-143022.json \ -k blt********
Result: Only the 20 failed entries are retried, successful ones are skipped.
Use Case 7: Asset Organization by Folder
Scenario: Publish only marketing assets in a specific folder.
Solution:
csdx cm:stacks:bulk-assets \ --operation publish \ --folder-uid cs_marketing_2026 \ --environments production \ --locales en-us \ -k blt********
Result: Only assets in the cs_marketing_2026 folder are published.
Use Case 8: Rollback Published Content
Scenario: After publishing 300 blog entries to production, you discover that some entries contain incorrect information and need to be unpublished immediately.
Solution:
# Step 1: Revert the publish operation using the operation log csdx cm:stacks:bulk-entries \ --revert ./bulk-operation
How it works:
- The --revert flag reads the operation log from the bulk-operation folder
- It automatically unpublishes all entries that were published in the last operation
- Restores entries to their previous version before publishing
- Only works with publish operations (cannot revert unpublish operations)
Result: All 300 blog entries are unpublished and reverted to their previous version, effectively rolling back the entire operation.
Important Notes:
- The bulk-operation folder stores detailed logs of the last operation only
- Each new operation overwrites the previous logs
- To preserve logs for audit purposes, copy the folder before running a new operation:
cp -r bulk-operation bulk-operation-backup-$(date +%Y%m%d-%H%M%S)
Use Case 9: Retry Failed Operations After Network Issues
Scenario: While publishing 500 product entries to production, a temporary network issue caused 75 entries to fail. You want to retry only the failed entries without re-processing the successful ones.
Solution:
# Step 1: Check the operation summary to identify failures # The CLI automatically logs failed operations # Step 2: Retry only the failed entries csdx cm:stacks:bulk-entries \ --retry-failed ./bulk-operation
How it works:
- The --retry-failed flag reads the failed operation logs from the bulk-operation folder
- It identifies all entries/assets that failed in the last operation
- Re-attempts the operation only for failed items
- Successful entries are skipped automatically
Result: The 75 failed entries are retried and successfully published, while the 425 successful entries are untouched.
Best Practices:
- Wait before retrying: If the failure was due to rate limiting or network issues, wait a few minutes before retrying
- Check error logs: Review the error messages in the operation logs to understand the root cause
- Fix underlying issues: If failures are due to invalid data, fix the content before retrying
- Monitor retry attempts: The CLI tracks retry counts and will stop after max retries (default: 5)
Common Retry Scenarios:
- Network timeouts or connection issues
- Temporary API rate limit errors (429)
- Server errors (5xx responses)
- Transient infrastructure issues
Non-retryable Scenarios (require manual intervention):
- Invalid content type UIDs (404)
- Missing required fields in entries
- Permission errors (403)
- Invalid API credentials (401)
Use Case 10: Automated Retry in a CI/CD Pipeline
Scenario: You have a CI/CD pipeline that publishes content, and you want to retry failures automatically.
Note The CLI does not read the --config file in this release, so you cannot change the retry count or rate limit. The CLI retries each failed request up to 3 times, then logs it for --retry-failed.
Solution:
# Initial publish attempt csdx cm:stacks:bulk-entries \ --operation publish \ --content-types product,article \ --environments production \ --locales en-us,es-es \ --publish-mode bulk \ -k blt******** \ --yes # If failures occur, retry only the failed items after 30 seconds sleep 30 csdx cm:stacks:bulk-entries --retry-failed ./bulk-operation --yes
Result: The second command retries only the items that failed in the first run. In bulk mode, the CLI does not log failures inside an accepted bulk job, so check the bulk publish status link for those items. Use --publish-mode single to log every failed item.
Use Case 11: Safe Multi-Stage Deployment with Rollback
Scenario: Deploy content to staging for testing, and if approved, promote to production. If issues are found in production, quickly rollback.
Solution:
# Step 1: Publish to staging csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post,article \ --environments staging \ --locales en-us \ -k blt******** # Backup the operation logs cp -r bulk-operation bulk-operation-staging-$(date +%Y%m%d-%H%M%S) # Step 2: After testing, promote to production csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post,article \ --environments production \ --locales en-us \ -k blt******** # Backup production operation logs cp -r bulk-operation bulk-operation-production-$(date +%Y%m%d-%H%M%S) # Step 3: If issues found, rollback production csdx cm:stacks:bulk-entries \ --revert ./bulk-operation-production-YYYYMMDD-HHMMSS
Result: Content is safely deployed with the ability to quickly rollback production while preserving staging state.
Content Filters
The CLI supports various filters to target specific entries based on their status and content state:
Non-Localized Filter
The non-localized filter identifies entries where non-localized fields have been updated in the master locale, requiring localized entries to be republished to maintain consistency.
How it works:
- Fetches all available locales from your stack
- Determines the master locale (first locale in the stack)
- For each entry, compares non-localized field values between the master locale and all other locales
- Returns entries where non-localized fields differ between locales
Use Case: When you update a non-localized field (like a status, category, or global setting) in the master locale, all localized versions of that entry should be republished to reflect the change.
Example:
# Publish entries where non-localized fields have been updated csdx cm:stacks:bulk-entries \ --operation publish \ --filter non-localized \ --content-types product \ --environments production \ -k blt*******
Note This filter automatically discovers all locales in your stack and doesn't require specifying the --locales flag.
Configuration
Using Config Files
Warning The --config flag accepts a JSON file path, but the CLI does not read the file in this release. Rate limits, retry counts and other options in the file have no effect. Pass each option as a flag. The CLI always sends up to 10 requests per second, 5 at a time, and retries a failed request up to 3 times.
The CLI ignores the example file below:
csdx cm:stacks:bulk-entries -c my-config.json -k blt********
Example Config File:
{
"operation": "publish",
"contentTypes": ["blog_post", "article"],
"environments": ["production", "staging"],
"locales": ["en-us", "es-es"],
"filter": "draft",
"publishMode": "bulk",
"branch": "main",
"rateLimit": {
"requestsPerSecond": 15,
"maxConcurrent": 5
},
"maxRetries": 3
}Examples
Basic Publish Operation
# Publish all entries of a content type csdx cm:stacks:bulk-entries \ --operation publish \ --content-types blog_post \ --environments production \ --locales en-us \ --stack-api-key blt******* # Publish assets csdx cm:stacks:bulk-assets \ --operation publish \ --environments production \ --locales en-us \ --stack-api-key blt*******
Basic Unpublish Operation
# Unpublish entries csdx cm:stacks:bulk-entries \ --operation unpublish \ --content-types blog_post \ --environments staging \ --locales en-us \ --stack-api-key blt*******
Best Practices
1. Test in Lower Environments First
Always test bulk operations in dev/staging before production:
# Test in dev first csdx cm:stacks:bulk-entries --operation publish --environments dev ... # Then staging csdx cm:stacks:bulk-entries --operation publish --environments staging ... # Finally production csdx cm:stacks:bulk-entries --operation publish --environments production ...
2. Use Config Files for Complex Operations
For operations with many flags, use config files for repeatability and version control.
3. Monitor Rate Limiter Logs
Pay attention to rate limiter messages to understand system behavior.
4. Start with Bulk Mode
Use bulk mode by default for efficiency, switch to single mode only when needed.
5. Keep Log Files
Save log files for auditing and potential rollback:
cp -r bulk-operation bulk-operation-backup-$(date +%Y%m%d)
6. Use Filters to Reduce Load
Apply filters to publish only necessary content:
--filter draft # Only unpublished entries --filter modified # Only entries modified since last publish
7. Batch Similar Operations
Group operations by content type, environment, or locale for better performance.
Limitations
- Retry and revert (--retry-failed, --revert) are not supported for cm:stacks:bulk-taxonomies. They work for bulk-entries and bulk-assets only, which use a different log format.
- Cross-publish, publishing content already live in one environment to another using --source-alias, is not supported for cm:stacks:bulk-taxonomies.
- Taxonomy publish operates at the taxonomy level. Publishing an individual term is not supported by the API.