Safe content migrations in production
A migration script does nothing until you run it, and once you do, it changes content immediately, and the only way to undo it is the rollback function you wrote. This lesson walks you through running your scripts safely, starting with a non-production environment, validating them against a fresh copy of production, and finally running them in production.
Before you start
Changing your content model touches live content, so always test everything in separate environments before committing to production: a development sandbox for your initial changes, then a staging environment for a final check. The following steps outline how to do it. Make sure you have the following ready:- Your migration scripts – see Create migration scripts for how to write them
- Node.js (LTS version)
- The data-ops
package – run it directly with
npx(as in the examples below) or install it locally
1. Create a non-production environment
Create a clone of your production environment to use it as your own development sandbox for testing.2. Run your scripts in the sandbox
With your scripts written and a sandbox to test in, run them against that sandbox first.- Environment ID – of the non-production environment you created in step 1.
- Management API key – with permissions for the entities you’re changing. Each environment has its own set of API keys.
- Migrations folder – the folder holding the scripts you wrote.
npx @kontent-ai/data-ops@latest migrations run \
--migrationsFolder my-first-migration \
--environmentId=<non-production-environment-id> \
--apiKey=<management-api-key> \
--allmigrations run shows a warning about potentially irreversible changes and asks you to confirm. Pass --skipConfirmation to skip the prompt in scripts or CI.
Instead of --all, you can target a specific run:
--name my-first-migration.js– a single named script.--next 1– the next pending migration only. Passing a higher number, for example--next 3, runs that many upcoming migrations.--range 1:5– a numeric or date range, for example--range T2026-01-01:T2026-06-30.
--all, --name, --next, or --range must be set.
Once your commands start getting long, consider passing parameters via a JSON file with --configFile params.json that sets environmentId, apiKey, and migrationsFolder, so you don't repeat them on every call.
status.json file alongside your migrations, so each migration runs exactly once. Use --force to re-run a completed migration.
When the command finishes, your changes are applied in the sandbox, and any failures are listed in the CLI output. Fix anything that failed and confirm the result in the sandbox before moving on.3. Validate against a fresh copy of production
Once your migration scripts work as expected in the sandbox, validate them against the current production data. Create a new staging environment by cloning the production environment. Then run your migration scripts against the new staging environment, using the command from step 2 with the staging environment ID. The production environment has likely changed since you wrote the migration scripts, so this run checks your scripts against the latest production content.4. Test the rollback
The staging environment created in step 3, a fresh copy of production, is a great place to test your rollback. Undo the migration you just ran by adding--rollback and naming the script:
npx @kontent-ai/data-ops@latest migrations run \
--migrationsFolder my-first-migration \
--environmentId=<staging-environment-id> \
--apiKey=<management-api-key> \
--name my-first-migration.js \
--rollbackrollback function instead of its run. Check that the environment is back to its previous state. If the rollback function is empty, the command completes without changing anything, which is exactly what you want to discover here rather than in production.
5. Run the migration scripts against production
If anyone changed content in production since the content freeze, repeat steps 3 and 4 using a fresh production clone first.--rollback before going any further.6. Clean up
You’re done with the migration, and your production content model is updated. The content freeze is over. Your content creators can make changes again. All that’s left to do is to clean up. Delete the staging and development environments since they’re no longer needed. The next time you need to perform a content migration, you’ll create new ones. If cloning your non-production environments for every migration takes too long, you can reuse them instead. Use Sync across environments using data-ops and Migrate content to other environments to bring them closer to production before your next migration. A fresh clone is still the safest way to validate before your final production run.See it in practice
The Kontent.ai migrations examples
repository has ready-to-run sample scripts covering common setup tasks, including collections, live preview, taxonomies, assets, snippets, content types and their language variants, and spaces, each with a rollback.
- Clone the repository.
- Install dependencies (
npm ci). - Copy
exampleParams.jsontomigrationsParams.jsonand fill in the details of a non-production environment. - Work through the scripts one at a time with
npm run migrate:next 1, or runnpm run migrate:allto execute them all at once.