Verify the safety of changes to your graph
Certain changes to your GraphQL schema (such as removing a field or type) might break one of your application's clients. Apollo Studio provides schema checks to help you identify breaking changes before you make them, and to help you identify when a potentially dangerous change won't break anything.
You can review the results of schema checks inside Studio, helping you make informed decisions about evolving your graph:
Schema checks are a paid feature that's available as part of Apollo Studio Team and Enterprise plans.
Apollo Studio can perform the following types of schema checks:
Operation checks. Compare your proposed schema changes against historical operations to verify whether the changes will break any of your graph's active clients.
Most of this article covers operation checks. For details on composition checks, see this section.
To enable schema checks for your graph, do the following if you haven't yet:
- Register your production graph's schema with Apollo.
- Enable metrics reporting to Apollo Studio from your production graph. Studio uses these metrics to help determine when a type or field can be modified or removed safely.
- Install the Rover CLI in your development environment and authenticate it with Apollo Studio.
Let's say you've made local changes to your GraphQL server's schema. After you complete the prerequisites, you can run schema checks against those changes with the
rover graph check command.
rover graph check command looks like this:
rover graph check docs-example-graph@current --schema ./schema.graphql
It requires the following:
Your registered graph's graph ref. This is available from your graph's Schema tab in Studio:
The locally modified version of your schema. In the command above, the schema is provided via a
If your schema is not in a standalone
.graphqlfile, you can run your GraphQL server locally and pipe its schema directly from
rover graph introspect, like so:
rover graph introspect http://localhost:4000 | rover graph check my-graph-name@my-variant-name --schema -
Try changing something in the local version of your schema and see what happens! If everything is set up correctly, the command's output looks similar to the output shown in The check response.
When you run
rover graph check:
- Apollo Studio generates a diff between your local schema and the registered schema for the variant you're checking against.
- Studio uses this diff to determine whether the changes affect any operations that have been executed against your graph within a customizable time window (by default, this is the last seven days).
- Studio returns the diff, along with a list of the operations that are affected by the changes.
- Rover prints the result of the check and returns a non-zero exit code if at least one breaking change is found.
rover graph check outputs the diff of all detected schema changes and highlights breaking changes:
$ rover graph check docs-example-graph@current --schema ./schema.graphql Validated the proposed subgraph against metrics from docs-example-graph@current Compared 1 schema changes against 24 operations ┌────────┬────────────────────┬─────────────────────────────────────────────────────────┐ │ Change │ Code │ Description │ ├────────┼────────────────────┼─────────────────────────────────────────────────────────┤ │ PASS │ FIELD_CHANGED_TYPE │ field `Query.books`: type `[Book]` changed to `[Book!]` │ └────────┴────────────────────┴─────────────────────────────────────────────────────────┘ View full details at https://studio.apollographql.com/service/docs-example-graph/checks/<DETAILS>
Each change to the schema is labeled either
Note: Because breaking changes are detected by analyzing recent operations, your GraphQL server must be pushing analytics to Apollo Studio for schema checks to work. If there are no operation metrics to compare against, all potentially dangerous schema changes are labeled
The output also includes a Studio URL that provides full details on the changes and their impact on existing clients and operations:
If you've integrated schema checks with your GitHub PRs, the "Details" link in your GitHub check takes you to this same details page.
Occasionally, schema checks might flag a change that you know is safe. For example, you might change an input type's field from nullable to non-null when you are certain that none of your clients ever provides a null value for that field.
In cases like this, you can override a flagged change in Apollo Studio from the associated check's details page:
You override flagged changes on an operation-by-operation basis. For each operation with flagged changes, you can override those changes in the following ways:
- Mark the changes as safe. In this case, schema checks will not flag these exact changes for the operation in any future execution. This effectively "approves" the changes for the operation.
- If a future check detects approved changes along with new unsafe changes to the operation, the new unsafe changes will be flagged.
- Ignore the operation. In this case, schema checks will completely ignore the operation when checking all changes in any future execution.
- This option is useful when you know an operation originates only from clients or client versions that you don't actively support.
You can rerun checks from inside Studio:
When you do, the new check uses the current check configuration options, regardless of the configuration at the time of the original check. Similarly, the new check's time window is based on the current time, not the time when the original check ran.
The new check incorporates any changes made to excluded or included clients, checked variants, and any operations marked as safe or ignored.
Note: If you've integrated schema checks with your GitHub PRs, a rerun of the check also updates the status of the check in Github.
If you have a federated graph, you run schema checks with the
rover subgraph check command (instead of
rover graph check):
rover subgraph check docs-example-graph@current --schema ./schema.graphql --name products
In addition to the arguments required by
subgraph check requires the
--name of the particular subgraph you're performing checks for.
To obtain your running subgraph's schema via introspection, use
subgraph introspectinstead of
graph introspect. This preserves federation-specific directives that are required for composition.
When you run
subgraph check, Apollo Studio performs a composition check before it performs operation checks. A composition check verifies that changes you make to a subgraph schema are compatible with your other subgraph schemas, enabling them to compose into a supergraph schema (learn more).
If a composition check fails, Studio does not then perform operation checks for the provided schema.
Results of both check types are available in Studio from your graph's Checks tab:
You can click on a composition check to view its result. If composition succeeded, you can view the composed supergraph schema. Regardless of success, you can view the subgraph schema.
rover subgraph check command returns a nonzero result if a composition check or operation check fails.
Schema checks are especially useful when you add them to your CI pipeline (such as Jenkins or CircleCI). By doing so, you can obtain check results and display them directly on your team's pull requests.
We recommend defining a separate CI job for each variant of your schema (production, staging, etc.) that you want to validate your changes against. The
rover graph check command returns a non-zero exit code when it detects a breaking change, meaning the job fails when the check fails.
rover config auth command is interactive, which means you shouldn't use it in CI environments. Instead, you can authenticate Rover with Studio by setting the
APOLLO_KEY environment variable in CI. For details, see Configuring Rover.
The following config defines a schema check job for a CircleCI pipeline. Your config's syntax varies depending on your CI tool, but the job's steps are the same.
version: 2 jobs: # ...other jobs... # Define a separate job for each environment you validate against. check_against_staging: docker: - image: circleci/node:12 steps: - checkout - run: npm install # Start the GraphQL server. If a different command is used to # start the server, use it in place of `npm start` here. - run: name: Starting server command: npm start background: true # Make sure the server has enough time to start up before running # commands against it. - run: sleep 5 # In CI environments, this command authenticates with the `APOLLO_KEY` # environment variable. - run: rover graph check docs-example-graph@current --schema ./schema.graphql
If you're using GitHub, you can install the Apollo Studio GitHub app. This app enables Apollo Studio to send a webhook back to your GitHub project on each call to
rover graph check, providing built-in pass/fail status checks on your pull requests:
If you're using GitHub Enterprise, Bitbucket, or another version control service, we recommend setting up your CI tool to post a comment on each pull request with the results of schema checks. By surfacing schema diffs and breaking changes directly in your PR, you can avoid searching your CI logs to determine why a check failed.
Not every change to a schema is a potentially breaking change. Additive changes (such as adding a field to a type) are typically safe and do not affect active clients. Deletions and modifications (such as removing a field or changing a return type), however, can break clients that use affected types and fields.
These changes remove a schema element. If a removed element is actively being used by an operation, your graph will return an error to affected clients.
|A field used by at least one operation was removed.|
|A scalar or object used by at least one operation was removed.|
|An argument used by at least one operation was removed from a field.|
|A type was removed from a union used by at least one operation.|
|A field was removed from an input type. That field is referenced by an argument on another field that's used by at least one operation.|
|A value was removed from an enum used by at least one operation.|
|An object was removed from an interface used by at least one operation.|
These changes add a required input to a schema element. If an operation is actively using an element of your graph and doesn't add the new required input argument, the graph will return an error to affected clients.
|A non-nullable argument was added to field that's used by at least one operation.|
|A non-nullable field was added to an input object used by at least one operation.|
These changes update an existing schema element. If an operation is actively using an element that is updated, the operation might start receiving an error from your graph. It also might receive an unexpected result.
Note: In some cases, in-place updates are compatible with affected clients at runtime (such as a type rename or a conversion from an object to an interface that uses the same fields). However, schema checks still marks these as breaking changes, because validation does not have enough information to ensure that they are safe.
|An existing field used by at least one operation changed its type.|
|An existing field of an input object changed its type. That field is referenced by an argument on another field that's used by at least one operation.|
|An existing type used by at least one operation changed its "kind." For example, an object type was changed to a union type.|
|An existing argument on a field used by at least one operation changed its type.|
These changes update the default value for an argument. If an operation is using an element of your graph and does not specify a value for this argument, the operation might get an unexpected result when the schema is updated if it was relying on the original default value.
|An existing field used by at least one operation had a default value added or changed.|
These changes are detected by schema checks, but they are "safe." They never affect the behavior of any existing clients if deployed.
|A field was added to an existing type.|
|A type was added to the schema.|
|A value was added to an enum. If clients contain a switch statement on the enum's value and do not include a |
|A type was added to a union used by at least one operation.|
|An interface was applied to an object used by at least one operation.|
|A nullable argument was added to an existing field.|
|A nullable field was added to an existing input object.|
|An existing field was deprecated.|
|A previously deprecated field is no longer deprecated.|
|The specified reason for a field's deprecation changed.|
|An existing enum was deprecated.|
|A previously deprecated enum is no longer deprecated.|
|The specified reason for an enum's deprecation changed.|
|An existing type's description changed.|
|An existing field's description changed.|
|An existing enum value's description changed.|
|An existing argument's description changed.|