The CLI Bulk Operations plugin provides commands to publish and unpublish entries and assets in bulk. It manages API rate limits, retries failed requests, and supports processing large content sets.
Managing content at scale introduces operational challenges that are difficult to handle manually, such as:
The Bulk Operations plugin addresses these challenges by providing a structured, automated mechanism to execute and monitor bulk content actions.
By the end of this guide, you can:
Before you begin, make sure you have the following:
# Install Contentstack CLI
npm install -g @contentstack/cli
# Install bulk operations plugin
csdx plugins:install @contentstack/cli-bulk-operations
# Verify installation
csdx cm:stacks:bulk-entries --help# 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*******# Unpublish entries
csdx cm:stacks:bulk-entries \
--operation unpublish \
--content-types blog_post \
--environments staging \
--locales en-us \
--stack-api-key blt*******Perform bulk operations on entries with advanced filtering and publishing options.
csdx cm:stacks:bulk-entries [OPTIONS]| Flag | Description | Example |
|---|---|---|
| --operation | Specifies whether to publish or unpublish content. | --operation publish |
| --environments | Specifies one or more environments where the entries or assets should be published. Separate multiple environments with spaces. | --environments prod staging |
| --locales | Specifies one or more locale codes for which the entries or assets should be published. Separate multiple locales with spaces. | --locales en-us fr-fr |
| -k, --stack-api-key | API key of the source stack. You must use either the --stack-api-key flag or the --alias flag. | -k blt********* |
| -a, --alias | Uses the name of a saved Management Token to authenticate the command. The command can only access the branches allowed for that token. This option can be used as an alternative to --stack-api-key. | -a my-token |
| Flag | Description | Default |
|---|---|---|
| --content-types | Specifies the content type UIDs to include in the operation. If not provided, the operation applies to all content types in the stack. | - |
| --filter | Filter entries by status: draft, modified, unpublished, non-localized | - |
| --include-variants | Includes entry variants (alternate versions of a base entry) in the bulk operation. By default, only base entries are processed. | false |
| --api-version | Specifies the Content Management API version used for publishing. Use version 3.2 when publishing entries with nested references, otherwise, use the default version. | 3.2 |
Filter values:
| Flag | Description | Default |
|---|---|---|
| --publish-mode | Publish mode: bulk (uses Bulk Publish API) or single (individual API calls) | bulk |
| --branch | 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. | main |
| --source-env | Specifies the environment from which content should be copied when publishing to another environment. Use this option for cross-environment publishing. | - |
| --source-alias | Alias name for source environment delivery token (required for cross-publish). Add delivery token using: csdx auth:tokens:add | - |
| -y, --yes | Skips interactive confirmation prompts and runs the command immediately using the provided options. Useful for automation and scripts. | false |
| -c, --config | Specifies the path to a JSON configuration file that defines the options for the command. Use this file instead of passing multiple CLI flags for a single run. | - |
| --retry-failed | Retries only the entries or assets that failed in a previous bulk operation, using the log file generated during that run. | - |
| --revert | Reverts a previous bulk publish operation using its log files, undoing the entries or assets published in that run. | - |
| --bulk-operation-file | Folder path to store operation logs. | bulk-operation |
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 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 \
--api-key blt******* \
--environment production \
--type deliveryThen 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-operation8. Revert a publish operation
# Revert (unpublish) previously published entries
csdx cm:stacks:bulk-entries \
--revert ./bulk-operation9. 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*******Use this command to publish or unpublish assets in bulk, with the option to filter by folder.
csdx cm:stacks:bulk-assets [OPTIONS]Same as bulk entries, see Required Options .
| Flag | Description | Example |
|---|---|---|
| --folder-uid | The UID of the Assets folder that contains the assets you want to publish. Default: cs_root | --folder-uid cs_root |
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 the Bulk Entries section 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-operation6. Revert an asset publish operation
# Revert (unpublish) previously published assets
csdx cm:stacks:bulk-assets \
--revert ./bulk-operationUses Contentstack's native Bulk Publish APIs.
Best For:
Example:
csdx cm:stacks:bulk-entries \
--operation publish \
--content-types blog_post \
--environments production \
--locales en-us \
-k blt*******Makes individual API calls for each item with intelligent rate limiting.
Best For:
Example:
csdx cm:stacks:bulk-entries \
--operation publish \
--content-types blog_post \
--environments production \
--locales en-us \
--publish-mode single \
-k blt*******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.
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.
Step 1: Create a Delivery Token in Contentstack
Step 2: Add Token to CLI
csdx auth:tokens:add \
-a <alias-name> \
--delivery-token <your-delivery-token> \
--api-key <your-stack-api-key> \
--environment <source-environment> \
--type deliveryExample:
# Add production delivery token
csdx auth:tokens:add \
-a prod-delivery \
--delivery-token csaf3444***** \
--api-key blt******** \
--environment production \
--type delivery
# Add staging delivery token
csdx auth:tokens:add \
-a staging-delivery \
--delivery-token csaf3444***** \
--api-key blt******** \
--environment staging \
--type deliveryStep 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 achu3444***** \
--environments production \
--locales en-us \
-k blt********# List all stored tokens (including delivery tokens)
csdx auth:tokens
# Remove a delivery token
csdx auth:tokens:remove -a staging-deliveryScenario: 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).
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 --yesScenario: 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 \
--api-key blt******** \
--environment staging \
--type deliverySolution:
# 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.
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.
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 across 10 locales and three environments result in 1,500 publish operations. completed in about 5 minutes via batching.
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.
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.
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-operationHow it works:
Result: All 300 blog entries are unpublished and reverted to their previous version, effectively rolling back the entire operation.
Important Notes:
cp -r bulk-operation bulk-operation-backup-$(date +%Y%m%d-%H%M%S)
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-operationHow it works:
Result: The 75 failed entries are retried and successfully published, while the 425 successful entries are untouched.
Best Practices:
Common Retry Scenarios:
Non-retryable Scenarios (require manual intervention):
Scenario: You have a CI/CD pipeline that publishes content, and you want to automatically retry failures with custom retry logic.
Solution:
# config.json
{
"operation": "publish",
"contentTypes": ["product", "article"],
"environments": ["production"],
"locales": ["en-us", "es-es"],
"publishMode": "bulk",
"maxRetries": 3,
"retryDelay": 5000,
"rateLimit": {
"requestsPerSecond": 10,
"maxConcurrent": 3
}
}
# Initial publish attempt
csdx cm:stacks:bulk-entries -c config.json -k blt******** --yes
# If failures occur, automatically retry after 30 seconds
sleep 30
csdx cm:stacks:bulk-entries --retry-failed ./bulk-operation --yesConfiguration Options:
Result: Failed operations are automatically retried with controlled rate limiting. This approach helps handle temporary failures more reliably..
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-HHMMSSResult: Content is safely deployed with the ability to quickly rollback production while preserving staging state.
Configuration files allows you to reuse and automate complex bulk operations without repeating CLI flags.
Use config files when:
Avoid config files when:
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",
"apiVersion": "3.2",
"rateLimit": {
"requestsPerSecond": 15,
"maxConcurrent": 5
},
"maxRetries": 3,
"maxPolls": 300
}This section helps you diagnose and recover from common bulk operation failures.
Solution: The adaptive rate limiter should prevent this, but if it occurs:
Solution:
Solution:
Solution:
export NODE_OPTIONS=--max-old-space-size=4096$env:NODE_OPTIONS="--max-old-space-size=4096"Error: Invalid configuration: errors
Solution: Validate your config file or flags:
Error: Cross-publish requires --source-alias flag with a delivery token
Solution:
csdx auth:tokens:add \
-a <alias-name> \
--delivery-token <token> \
--api-key <api-key> \
--environment <source-env> \
--type deliveryError: No token found for alias 'staging-delivery'
Solution:
Error: Alias 'my-token' is not a delivery token (type: management)
Solution:
You're using a management token alias instead of a delivery token. Cross-publish requires a delivery token:
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 for large-scale or multi-environment operations, and single mode only for small batches requiring detailed debugging. Using single mode for large batches can significantly increase execution time, trigger API rate limits, and cause partial failures that are harder to recover.
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 publish7. Batch Similar Operations
Group operations by content type, environment, or locale for better performance.