Content and Component Migrations with storyblok-migrate
Storyblok is the first headless CMS that works for developers & marketers alike.
Update: We recommend to use the new content migration functionality of Storyblok's CLI.
First and foremost Storyblok is known for its great UI. The wonderful Visual Editor is one of the features which sets Storyblok apart from its competitors. But also the quick and easy way how you can make updates to the schema of your content models via the UI directly while editing the content of your site can make the life of content editors a lot easier.
Although it is nice to have the option to manage the structure of your site via the UI, especially with bigger projects with a lot of people working on the same site, it can become tedious to keep track of all the changes to the schema of the site when relying solely on the UI for managing your content types. In such cases it's often times favorable to store the schema of you content types in code to be able to keep track of changes via version control.
Additionally, sometimes you might want to refactor the structure of your site and its components. In a lot of traditional content management systems and frameworks there is the concept of migrations, either directly built in from the start or available via third party plugins. For example the PHP framework Laravel has migrations built in. The CMS Drupal has update hooks to serve a similar purpose.
With the storyblok-migrate
npm package it is now possible to define content migrations which are automatically applied to your stories for Storyblok. This makes it straight forward to refactor certain content types and to rename fields or even changing the type of a field.
Installing storyblok-migrate
storyblok-migrate
is available as a npm package. You can install it as a dependency of your project, by running the following command in your CLI of choice.
After installing the dependency you have to create a new directory named storyblok
at the root level of your project (but you can change the name and the location of this directory via an optional configuration file if you want).
Configuration
In the following code snippet you can see an example storyblok.config.js
file with all its options set to its default values.
All the configuration options of storyblok-migrate
are optional. But you have to make sure that at least the STORYBLOK_OAUTH_TOKEN
and your STORYBLOK_SPACE_ID
environment variables are set correctly. It is recommended to do this via an .env
file which you create at the root of your project.
At least if your source code is public, you must keep your OAuth token private! I highly recommend you to add the .env
file to your .gitignore
list if you're using Git.
The dryRun
option makes it possible to see what would happen when running a certain command without actually changing anything in Storyblok. You can either append --dry-run
when running a command or setting this option to true
to run your commands in dry run mode.
Defining components in code
One of the core principles of storyblok-migrate
is that every component is defined in code. This means you don’t use the Storyblok UI for creating new components or updating existing ones. Ideally, you only make changes to your components in one place: the component definitions in your code.
Above you can see an example Storyblok component as it looks when defined as a JavaScript object. You may wonder why you should even consider abandoning the convenience of the great Storyblok interface for a seemingly complicated approach like this. But as we will see, this method has a number of advantages.
For example: if you change the name of a field or if you add a new field, you most likely also have to update the code of your website. If you have specified the schema of your components in your code base as well, all of your changes are made in one place. This makes it a lot easier to track and sometimes even to revert changes if something unforeseen happens.
Additionally you get all the other benefits of version control. It’s much easier for multiple developers to work on the same site. All changes to the structure of the site are reflected in a commit to the code base. That way it is much less likely that a change to the schema of the site breaks the code of another developer. It happened more than once in my career that somebody accidentally deleted some field or even a whole content type. When having them all stored in code and even disallow changing the schema in the UI this problem is a problem from the past.
Running component migrations
After you have defined all your content types in code you’re ready to run the migration script in order to push them to Storyblok.
If you run npx storyblok-migrate
without any parameters you start the guided UI mode which asks you some questions about what you want to do.
But you can also use parameters to immediately run a certain task.
Content migrations
The second vital part of storyblok-migrate
is the possibility to run content migrations. What this means is that you can update the content structure of your website whenever you change the schema of one of your components. Imagine you change the name of a textfield – content migrations make it possible to update all of your content, move the data from the old field to the new one and delete the old one.
Above you can see how you can define a content migration function inside of the component definition file. All the functions specified in the migrations
array are run one after another. There is no restriction what those migration functions are allowed to do. They get passed in an object with the content
of the current component and you're free to modify it in whichever way you want. It is recommended to add a check at the beginning of your migration function to make sure to only run it when its needed.
Helper scripts
storyblok-migrate
also has some built in helper scripts for backing up your content and exporting components from Storyblok.
By default backups are stored in a directory named backup
but you can change the location by changing the backupDirectory
configuration option.
You can use the command above to initially get started with using storyblok-migrate
. This will automatically generate your component definitions in storyblok
based on the schema of the components you've created in Storyblok. But be careful: this command replaces existing component definitions you've already created earlier. But you can specify which components you want to export: npx storyblok-component-export article,product
.
Roadmap
Currently storyblok-migrate
, although 100% functional, is still in a testing phase. Some of its features might not be very well optimized for very large scale sites with hundreds or even thousands of stories. The next steps on the roadmap to v1.0.0 are optimizations and new features like versioning of content migrations, rolling back after a faulty migration and importing content from third party sources like other content management systems or even feeds.
Wrapping it up
Being able to automatically migrate your content and field types makes it easier to work on large scale websites where multiple developers work on the same code base and multiple persons are responsible to work on the structure of the site.
But it also comes with a price: it makes it much harder, or, depending on the skills of the person in charge, maybe even impossible, for a content editor to quickly make a change to the schema of the site. Oftentimes this is a trade-off worth taking in order to guarantee that this person doesn't accidentally break the site. But in other situations it might cripple the content editors in their work.
If you decide to use storyblok-migrate
please let me know if it works for your use case and which features you think are still missing.