Config Sync

Strapi config-sync plugin

This plugin is a multi-purpose tool to manage your Strapi database records through JSON files. Mostly used to version control config data for automated deployment, automated tests and data sharing for collaboration purposes.

NPM Version Monthly download on NPM CI build status codecov.io

Table of Contents

✨ Features

  • CLI - config-sync CLI for syncing the config from the command line
  • GUI - Settings page for syncing the config in Strapi admin
  • Partial sync - Import or export only specific portions of config
  • Custom types - Include your custom collection types in the sync process
  • Import on bootstrap - Easy automated deployment with importOnBootstrap
  • Exclusion - Exclude single config entries or all entries of a given type
  • Diff viewer - A git-style diff viewer to inspect the config changes

⏳ Installation

Install the plugin in your Strapi project.

# using yarn
yarn add strapi-plugin-config-sync

# using npm
npm install strapi-plugin-config-sync --save

Add the export path to the watchIgnoreFiles list in the config/admin.js file. This way your app won't reload when you export the config in development.

config/admin.js:
module.exports = ({ env }) => ({
  // ...
  watchIgnoreFiles: [
    '**/config/sync/**',
  ],
});

After successful installation you have to rebuild the admin UI so it'll include this plugin. To rebuild and restart Strapi run:

# using yarn
yarn build
yarn develop

# using npm
npm run build
npm run develop

The Config Sync plugin should now appear in the Settings section of your Strapi app.

To start tracking your config changes you have to make the first export. This will dump all your configuration data to the /config/sync directory. You can export either through the CLI or Strapi admin panel

Enjoy 🎉

🖐 Requirements

Complete installation requirements are the exact same as for Strapi itself and can be found in the Strapi documentation.

Supported Strapi versions:

  • Strapi 4.14.4 (recently tested)
  • Strapi ^4.x (use strapi-plugin-config-sync@^1.0.0)
  • Strapi ^3.4.x (use strapi-plugin-config-sync@0.1.6)

💡 Motivation

In Strapi we come across what I would call config types. These are models of which the records are stored in our database, just like content types. Though the big difference here is that your code ofter relies on the database records of these types.

Having said that, it makes sense that these records can be exported, added to git, and be migrated across environments. This way we can make sure we have all the data our code relies on, on each environment.

Examples of these types are:

  • Admin roles (admin::role)
  • User roles (plugin::users-permissions.role)
  • Admin settings (strapi::core-store)
  • I18n locale (plugin::i18n.locale)

This plugin gives you the tools to sync this data. You can export the data as JSON files on one env, and import them on every other env. By writing this data as JSON files you can easily track them in your version control system (git).

With great power comes great responsibility - Spider-Man

🔌 Command line interface (CLI)

Add the config-sync command as a script to the package.json of your Strapi project:

"scripts": {
  // ...
  "cs": "config-sync"
},

You can now run all the config-sync commands like this:

# using yarn
yarn cs --help

# using npm
npm run cs --help

⬆️ Import ⬇️ Export

Command: import Alias: i

Command: export Alias: e

These commands are used to sync the config in your Strapi project.

Example:

# using yarn
yarn cs import
yarn cs export

# using npm
npm run cs import
npm run cs export
Flag: -y, --yes

Use this flag to skip the confirm prompt and go straight to syncing the config.

[command] --yes
Flag: -t, --type

Use this flag to specify the type of config you want to sync.

[command] --type user-role
Flag: -p, --partial

Use this flag to sync a specific set of configs by giving the CLI a comma-separated string of config names.

[command] --partial user-role.public,i18n-locale.en
Flag: -f, --force

If you're using the soft setting to gracefully import config, you can use this flag to ignore the setting for the current command and forcefully import all changes anyway.

[command] --force

↔️ Diff

Command: diff | Alias: d

This command is used to see the difference between the config as found in the sync directory, and the config as found in the database.

Example:

# using yarn
yarn cs diff

# using npm
npm run cs diff
Argument: <single>

Add a single config name as the argument of the diff command to see the difference of that single file in a git-style diff viewer.

Example:

# using yarn
yarn cs diff user-role.public

# using npm
npm run cs diff user-role.public

🖥️ Admin panel (GUI)

This plugin ships with a React app which can be accessed from the settings page in Strapi admin panel. On this page you can pretty much do the same as you can from the CLI. You can import, export and see the difference between the config as found in the sync directory, and the config as found in the database.

Pro tip: By clicking on one of the items in the diff table you can see the exact difference between sync dir and database in a git-style diff viewer.

Config diff in admin

⌨️ Usage / Workflow

This plugin works best when you use git for the version control of your Strapi project.

The following workflows are assuming you're using git.

Intro

All database records tracked with this plugin will be exported to JSON files. Once exported each change to the file or the record will be tracked. Meaning you can now do one of two things:

  • Change the file(s), and run an import. You have now imported from filesystem -> database.
  • Change the record(s), and run an export. You have now exported from database -> filesystem.

Local development

When building a new feature locally for your Strapi project you'd use the following workflow:

  • Build the feature.
  • Export the config.
  • Commit and push the files to git.

Deployment

When deploying the newly created feature - to either a server, or a co-worker's machine - you'd use the following workflow:

  • Pull the latest file changes to the environment.
  • (Re)start your Strapi instance.
  • Import the config.

Production deployment

The production deployment will be the same as a regular deployment. You just have to be careful before running the import. Ideally making sure the are no open changes before you pull the new code to the environment.

🚀 Config types

By default the plugin will track 4 (official) types.

To track your own custom types you can register them by setting some plugin config.

Default types

These 4 types are by default registered in the sync process.

Admin role

Config name: admin-role | UID: code | Query string: admin::role

User role

Config name: user-role | UID: type | Query string: plugin::users-permissions.role

Core store

Config name: core-store | UID: key | Query string: strapi::core-store

I18n locale

Config name: i18n-locale | UID: code | Query string: plugin::i18n.locale

Custom types

Your custom types can be registered through the customTypes plugin config. This is a setting that can be set in the config/plugins.js file in your project.

Read more about the config/plugins.js file here.

You can register a type by giving the customTypes array an object which contains at least the following 3 properties:

customTypes: [{
  configName: 'webhook',
  queryString: 'webhook',
  uid: 'name',
}],

The example above will register the Strapi webhook type.

Config name

The name of the config type. This value will be used as the first part of the filename for all config of this type. It should be unique from the other types and is preferably written in kebab-case.

Key: configName

required: YES | type: string

Query string

This is the query string of the type. Each type in Strapi has its own query string you can use to programatically preform CRUD actions on the entries of the type. Often for custom types in Strapi the format is something like api::custom-api.custom-type.

Key: queryString

required: YES | type: string

UID

The UID represents a field on the registered type. The value of this field will act as a unique identifier to identify the entries across environments. Therefore it should be unique and preferably un-editable after initial creation.

Mind that you can not use an auto-incremental value like the id as auto-increment does not play nice when you try to match entries across different databases.

If you do not have a single unique value, you can also pass in an array of keys for a combined uid key. This is for example the case for all content types which use i18n features (An example config would be uid: ['productId', 'locale']).

Key: uid

required: YES | type: string | string[]

Relations

The relations array specifies the relations you want to include in the sync process. This feature is used to sync the relations between roles and permissions. See https://github.com/boazpoolman/strapi-plugin-config-sync/blob/master/server/config/types.js#L16.

Example:

{
  configName: 'admin-role',
  queryString: 'admin::role',
  uid: 'code',
  relations: [{
    queryString: 'admin::permission',
    relationName: 'permissions',
    parentName: 'role',
    relationSortFields: ['action', 'subject'],
  }],
},
Key: relations

required: NO | type: array

Components

This property can accept an array of component names from the type. Strapi Components can be included in the export/import process. With "." nested components can also be included in the process.

customTypes: [{
  configName: 'webhook',
  queryString: 'webhook',
  uid: 'name',
  components: ['ParentComponentA', 'ParentComponentA.ChildComponent', 'ParentComponentB']
}],
Key: components

required: NO | type: array

JSON fields

This property can accept an array of field names from the type. It is meant to specify the JSON fields on the type so the plugin can better format the field values when calculating the config difference.

Key: jsonFields

required: NO | type: array

🔍 Naming convention

All the config files written in the sync directory have the same naming convention. It goes as follows:

[config-type].[identifier].json
  • config-type - Corresponds to the configName of the config type.
  • identifier - Corresponds to the value of the uid field of the config type.

🔧 Settings

The settings of the plugin can be overridden in the config/plugins.js file. In the example below you can see how, and also what the default settings are.

config/plugins.js:
module.exports = ({ env }) => ({
  // ...
  'config-sync': {
    enabled: true,
    config: {
      syncDir: "config/sync/",
      minify: false,
      soft: false,
      importOnBootstrap: false,
      customTypes: [],
      excludedTypes: [],
      excludedConfig: [
        "core-store.plugin_users-permissions_grant",
      	"core-store.plugin_upload_metrics",
      	"core-store.strapi_content_types_schema",
	"core-store.ee_information",
      ],
    },
  },
});

Sync dir

The path for reading and writing the sync files.

Key: syncDir

required: YES | type: string | default: config/sync/

Minify

When enabled all the exported JSON files will be minified.

Key: minify

required: NO | type: bool | default: false

Soft

When enabled the import action will be limited to only create new entries. Entries to be deleted, or updated will be skipped from the import process and will remain in it's original state.

Key: soft

required: NO | type: bool | default: false

Import on bootstrap

Allows you to let the config be imported automaticly when strapi is bootstrapping (on strapi start). This setting can't be used locally and should be handled very carefully as it can unintendedly overwrite the changes in your database. PLEASE USE WITH CARE.

Key: importOnBootstrap

required: NO | type: bool | default: false

Custom types

With this setting you can register your own custom config types. This is an array which expects objects with at least the configName, queryString and uid properties. Read more about registering custom types in the Custom config types documentation.

Key: customTypes

required: NO | type: array | default: []

Excluded types

This setting will exclude all the config from a given type from the syncing process. The config types are specified by the configName of the type.

For example:

excludedTypes: ['admin-role']
Key: excludedTypes

required: NO | type: array | default: []

Excluded config

Specify the names of configs you want to exclude from the syncing process. By default the API tokens for users-permissions, which are stored in core_store, are excluded. This setting expects the config names to comply with the naming convention.

Key: excludedConfig

required: NO | type: array | default: ['core-store.plugin_users-permissions_grant', 'core-store.plugin_upload_metrics', 'core-store.strapi_content_types_schema', 'core-store.ee_information',]

🤝 Contributing

Feel free to fork and make a pull request of this plugin. All the input is welcome!

⭐️ Show your support

Give a star if this project helped you.

🌎 Community support

📝 Resources

Install now

npm install strapi-plugin-config-sync --save
Install now

♻️ CLI & GUI for continuous migration of config data across environments

252 GitHub stars

35k monthly downloads