Easily restore your project to a previous version with our new Instant One-click Backup Recovery

Hygraph
Docs

Environment diffing

Environment diffing is a functionality on the Management API that allows you to compare the schemas of two environments in a project.

When you work with multiple environments, you can use environment diffing as a way to know what changes were made in your development environment with respect to your master environment. That way you can know what changes you need to apply to your target environment so that it's the same as your source environment.

#How it works

Right after cloning, your environments are identical. After applying schema changes to your development environment, there is obviously a divergence. In order to find out what exactly those differences are and then apply them to your target environment, you can create a diff.

#1. Get the target and source environment names

In order to create a diff, you need to provide the names of the target and source environments.

The query to the ManagementApi would look similar to this:

query MyQuery {
viewer {
project(id: "<your-project-id>") {
environments {
name
id
}
}
}
}

#2. Create the diff

With this information, you can now create the diff. To differentiate between the environments master and dev, you can use the following query to the ManagementApi:

{
viewer {
project(id: "<your-project-id>") {
environment(name: "master") {
diff(environmentName: "development") {
changes
}
}
}
}
}

As a response, you will receive an array of objects - an ordered list of BatchMigrations, showing all the changes you need to apply to your target environment so that it's the same as your source environment.

#3. Apply the changes

To apply these changes to the target environment, you can use the following mutation in the ManagementApi:

mutation MyMutation($changes: [BatchMigrationChangeInput!]!) {
submitBatchChanges(
data: { environmentId: "<your-target-environment-id>", changes: $changes }
) {
migration {
id
}
}
}

In the above example, $changes is the environment variable with value equal to the changes object in the diff. This can be supplied like so:

$changes example in API Playground$changes example in API Playground

#Supported schema elements

The following schema elements are supported:

  • Models
  • Components
  • Locales
  • Simple fields
  • Relational fields
  • Enumerations
  • Stages
  • Union fields
  • Enumerable fields.

#Limitations

Please take into account the following limitations when using environment diffing.

#Schema changes to your master environment

Environment diffing is not the same as a merge in that it's not additive. Instead, it creates a diff to list all the necessary operations to turn the target environment (master) into the source environment (development). The diff is then applied, which replaces / overwrites one schema with another. It is important that you are aware of this at the time of applying changes to your target environment to avoid content loss.

Because of this, when you change something in the master environment that causes it not to be coherent with what is in development, the changes will always suggest deleting the piece of information it does not recognize to then create a new one.

Example situations:

  • Imagine you cloned your master environment last week to create a development environment and have spent some time since then working on development, making changes to the schema. During that time, you also applied schema changes to your master environment, which you did not mirror in development. Later on, when using environment diffing to get the diff and apply it, the diff will find those differences, and suggest deleting the changes you made to the schema in your master during the last week. Remember it does not merge, but replaces / overwrites.

  • Imagine your target environment schema has a field called Title Field, and after cloning you change its name to Title in master. In this case, environment diffing would suggest to delete Title and create Title Field. Doing this would result in schemas being the same in both environments, but you will have lost the content.

  • Imagine you delete a field in your development environment, then create a new field with the same name, environment diffing would not detect them as different fields at all.

Once you get the diff, you can apply it as is or, if necessary, edit it manually before applying to avoid content loss in the case of schema changes in the target environment.

It is important that you go over the diff changes one by one before you apply them, to make sure they are what you want to apply. Be extra cautious with deletions to avoid content loss.

#Required fields in development

Another thing to consider is the scenario where, after a clone, you make a field Required in your development environment, when content has already been created for the model that the field is a part of. In this case, you need to provide a migration value. This migration value will replace null in the previously created content. You will find this in the Validations section of your field details in the Schema editor:

Migration value in field validationsMigration value in field validations

In this case, environment diffing would suggest updating the field to required, but would not provide a migration value. Applying this change would fail because of the missing migration value. Since migration values are not stored, you will need to manually add the migration value to your change before applying it.

To do this manually, add "migrationValue": "value" like in the following example for a simple field:

{
"changes": [
{
"createSimpleField": {
"apiId": "newField",
"parentApiId": "Post",
"type": "STRING",
"displayName": "NewField",
"description": null,
"initialValue": null,
"tableRenderer": "GCMS_SINGLE_LINE",
"formRenderer": "GCMS_SINGLE_LINE",
"tableExtension": null,
"formExtension": null,
"formConfig": {},
"tableConfig": {},
"isList": false,
"isLocalized": false,
"isRequired": true,
"isUnique": false,
"isHidden": false,
"embeddableModels": [],
"visibility": "READ_WRITE",
"isTitle": false,
"position": 3,
"validations": null,
"embedsEnabled": null,
"migrationValue": "value"
}
}
]
}

This way, "value" will replace null after the diff.