Using Rover in CI/CD

Integrate Rover into continuous integration and deployment workflows


You can use Rover in any CI/CD environment that uses a Rover-supported operating system (Linux, macOS, or Windows). Most commonly, this is to run schema checks with rover graph check or rover subgraph check.

Apollo distributes Rover in three forms that are well-suited to CI:

  • Official Docker images on Docker Hub and GitHub Container Registry, with immutable tags pinned to each Rover release.

  • Apollo-published GitHub Actions on the GitHub Actions Marketplace, with one action per common Rover CI command. The Docker-based actions run inside the official image, so the Rover version is pinned to the action's release tag.

  • Native binary installers for Linux, macOS, and Windows. These are useful when Docker isn't available, when you need to run Rover on a non-Linux CI runner, or when you want to invoke Rover commands that don't have a dedicated action.

The rest of this page covers each option in detail, including end-to-end examples for the most common CI/CD providers:

If you're using Rover with a CI/CD provider not listed here, we'd love for you to share the steps by opening an issue or pull request.

Use API keys

Rover commands that communicate with GraphOS require an API key. GraphOS supports graph API keys, subgraph API keys, and personal API keys.

On your local development machine, use a personal API key and provide it to Rover with the rover config auth command.

In shared environments like CI, use a graph or subgraph API key and set it as an environment variable.

Choosing an integration method

You're using…Recommended approach
GitHub ActionsThe Apollo-published GitHub Actions (apollographql-gh-actions/*).
Any other CI provider that can run a container as a step (CircleCI, Bitbucket Pipelines, GitLab CI/CD, Jenkins with a Docker agent, etc.)The official Rover Docker image.
Windows or macOS CI runners, environments without Docker, or commands not covered by a published actionThe native binary installer.
Node.js-based workflowsThe npm distribution (@apollo/rover).

The Docker images and the lockstep GitHub Action tags are immutable per Rover release. Pin to a specific version (for example, ghcr.io/apollographql/rover:0.39.1 or apollographql-gh-actions/install-rover@rover-v0.39.1) so your pipeline behavior doesn't change when a new Rover version ships.

Docker images

Starting with Rover 0.39.1, Apollo publishes immutable Linux container images for every release. These images include the Rover binary as the default entry point running as a non-root user.

Bash
1# GitHub Container Registry
2docker pull ghcr.io/apollographql/rover:0.39.1
3
4# Docker Hub
5docker pull apollograph/rover:0.39.1
note
Always pin to a specific Rover version (such as 0.39.1) rather than a moving tag. Apollo enforces tag immutability per release, so a pinned tag is safe to use across long-lived pipelines.

Running a command

The default ENTRYPOINT is rover, so you can pass arguments to docker run directly:

Bash
1docker run --rm \
2  -e APOLLO_KEY \
3  -v "$PWD:/workspace" -w /workspace \
4  ghcr.io/apollographql/rover:0.39.1 \
5  subgraph check my-graph@prod --name products --schema ./schema.graphql
  • -e APOLLO_KEY forwards your API key from the host environment.

  • -v "$PWD:/workspace" -w /workspace mounts your repo so Rover can read schema files. Inside the container, paths are relative to /workspace.

The recommended approach for most CI providers (CircleCI, Bitbucket Pipelines, GitLab CI/CD, Jenkins with a Docker agent) is to set the image at the job or step level. This allows Rover commands to run as if they were on the host — see the per-provider examples below.

GitHub

note
Remember to authenticate using an environment variable. GitHub Actions uses project environments to set up secret environment variables. In your action, you choose a build.environment by name and set build.env variables using the saved secrets.

Apollo-published GitHub Actions

Apollo publishes GitHub Actions for common Rover CI commands, plus an installer action for everything else. For full input documentation, see each action's Marketplace listing:

Starting with Rover v0.39.1, the per-command actions are immutable Docker container actions that run inside the official ghcr.io/apollographql/rover image. Each Rover release publishes a matching @rover-v<version> tag for every action, so a single tag pins both the action and the Rover binary it runs.

note
Because the per-command actions are Docker container actions, they only run on Linux runners (for example, ubuntu-latest). To run Rover on macOS or Windows runners, use install-rover plus a run: step instead.

Full example using the Apollo-published GitHub Actions

YAML
1name: Rover Actions
2
3# Controls when the action will run. Triggers the workflow on push or pull request events
4on: [push, pull_request]
5
6# A workflow run is made up of one or more jobs that can run sequentially or in parallel
7jobs:
8  # This workflow contains a single job called "build"
9  build:
10    # The type of runner that the job will run on
11    runs-on: ubuntu-latest
12
13    # https://docs.github.com/en/actions/reference/encrypted-secrets
14    # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsenv
15    env:
16      APOLLO_KEY: ${{ secrets.APOLLO_KEY }}
17      APOLLO_VCS_BRANCH: ${{ github.head_ref }}
18      APOLLO_VCS_COMMIT: ${{ github.event.pull_request.head.sha }}
19
20    steps:
21      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
22      - uses: actions/checkout@v4
23
24      # Run a schema check against your graph
25      - uses: apollographql-gh-actions/rover-subgraph-check@rover-v0.39.1
26        with:
27          apollo-key: ${{ secrets.APOLLO_KEY }}
28          # This could also be provided via an environment variable or GitHub Action variable
29          graph-ref: ${{ secrets.APOLLO_GRAPH_REF }}
30          name: subgraph-name
31          # If you use a code-first subgraph, you can generate the schema in another step for use with this action
32          schema: ./path/to/schema.graphql
33          # Only run this command with the `background` setting if you have the Apollo Studio GitHub integration enabled on your repository
34          background: true
35
36      # Lint the subgraph schema.
37      - uses: apollographql-gh-actions/rover-subgraph-lint@rover-v0.39.1
38        with:
39          apollo-key: ${{ secrets.APOLLO_KEY }}
40          # This could also be provided via an environment variable or GitHub Action variable
41          graph-ref: ${{ secrets.APOLLO_GRAPH_REF }}
42          name: subgraph-name
43          # If you use a code-first subgraph, you can generate the schema in another step for use with this action
44          schema: ./path/to/schema.graphql
45
46      # Publish the subgraph to GraphOS
47      - uses: apollographql-gh-actions/rover-subgraph-publish@rover-v0.39.1
48        with:
49          apollo-key: ${{ secrets.APOLLO_KEY }}
50          # This could also be provided via an environment variable or GitHub Action variable
51          graph-ref: ${{ secrets.APOLLO_GRAPH_REF }}
52          name: subgraph-name
53          # If you use a code-first subgraph, you can generate the schema in another step for use with this action
54          schema: ./path/to/schema.graphql
55
56          # If running the first time, you will need to pass the `routing-url` parameter to the publish action.
57          # This URL is used for the Apollo Router to route requests to your subgraph.
58          routing-url: http://localhost:4000/graphql
59          # If the routing-url is invalid for one reason or another, you can also pass the `allow-invalid-routing-url` parameter to the publish action.
60          allow-invalid-routing-url: true
61
62          # If you are publishing to a Connectors-based subgraph, you can pass the `no-url` parameter to the publish action, which is equivalent to passing "" to `routing-url` and true to `allow-invalid-routing-url`.
63          no-url: true
64
65      # Publish persisted queries to GraphOS.
66      - uses: apollographql-gh-actions/rover-persisted-queries-publish@rover-v0.39.1
67        with:
68          apollo-key: ${{ secrets.APOLLO_KEY }}
69          graph-ref: ${{ secrets.APOLLO_GRAPH_REF }}
70          for-client-name: example-publish
71          manifest: ./path/to/persisted-queries-manifest.json
72
73      # Target a list by graph-id + list-id instead of graph-ref:
74      - uses: apollographql-gh-actions/rover-persisted-queries-publish@rover-v0.39.1
75        with:
76          apollo-key: ${{ secrets.APOLLO_KEY }}
77          graph-id: ${{ vars.APOLLO_GRAPH_ID }}
78          list-id: 1234-5678
79          for-client-name: example-publish
80          manifest: ./path/to/persisted-queries-manifest.json

Versioning the actions

  • @rover-v<version> — runs the matching Rover release. Both the action and Rover are released as immutable artifacts, so no SHA pinning is needed.

  • @v1 — pre-lockstep tag for the install action; accepts a version: input. Use this only if you need a Rover version older than v0.39.1, or if you can't use the Docker-based per-command actions (for example, on a Windows or macOS runner).

Installing Rover on non-Linux runners

If your job runs on macos-* or windows-* runners, or if you want to invoke a Rover command that doesn't have a published action, use install-rover to put rover on PATH and then call it directly:

YAML
1jobs:
2  check:
3    runs-on: ubuntu-latest # works equally well on macos-latest / windows-latest
4    env:
5      APOLLO_KEY: ${{ secrets.APOLLO_KEY }}
6    steps:
7      - uses: actions/checkout@v4
8      - uses: apollographql-gh-actions/install-rover@rover-v0.39.1
9      - run: rover graph check my-graph@prod --schema ./schema.graphql --background

Linux/macOS jobs using the curl installer

If you'd rather not depend on the Apollo-published action, you can install Rover with the shell installer. Note that GitHub Actions doesn't persist $PATH between run steps, so you must append Rover's bin directory to $GITHUB_PATH:

Bash
1echo "$HOME/.rover/bin" >> $GITHUB_PATH

Full example

YAML
1# .github/workflows/check.yml
2
3name: Check Schema
4
5# Controls when the action will run. Triggers the workflow on push or pull request events
6on: [push, pull_request]
7
8# A workflow run is made up of one or more jobs that can run sequentially or in parallel
9jobs:
10  # This workflow contains a single job called "build"
11  build:
12    # The type of runner that the job will run on
13    runs-on: ubuntu-latest
14
15    # https://docs.github.com/en/actions/reference/environments
16    environment: apollo
17
18    # https://docs.github.com/en/actions/reference/encrypted-secrets
19    # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsenv
20    env:
21      APOLLO_KEY: ${{ secrets.APOLLO_KEY }}
22      APOLLO_VCS_BRANCH: ${{ github.head_ref }}
23      APOLLO_VCS_COMMIT: ${{ github.event.pull_request.head.sha }}
24
25    # Steps represent a sequence of tasks that will be executed as part of the job
26    steps:
27      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
28      - uses: actions/checkout@v4
29
30      - name: Install Rover
31        run: |
32          curl -sSL https://rover.apollo.dev/nix/v0.39.1 | sh
33
34          # Add Rover to the $GITHUB_PATH so it can be used in another step
35          # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#adding-a-system-path
36          echo "$HOME/.rover/bin" >> $GITHUB_PATH
37      # only run this command with the `--background` flag if you have the Apollo Studio GitHub integration enabled on your repository
38      - name: Run check against prod
39        run: |
40          rover graph check my-graph@prod --schema ./test.graphql --background

Displaying schema check results on GitHub pull requests

If you use GitHub Actions to automatically run schema checks on every pull request as shown above, you can install the Apollo Studio GitHub app to provide links to the results of those checks alongside your other pull request checks:

To display schema check results on pull requests correctly, you need to make sure Rover associates the schema check execution with the pull request's HEAD commit, as opposed to the merge commit that GitHub adds. To guarantee this, set the APOLLO_VCS_BRANCH and APOLLO_VCS_COMMIT environment variables in your action's configuration, like so:

YAML
1env:
2  APOLLO_VCS_BRANCH: ${{ github.head_ref }}
3  APOLLO_VCS_COMMIT: ${{ github.event.pull_request.head.sha }}

CircleCI

CircleCI's docker executor runs any image. Use the official Rover image as the executor for steps that invoke Rover — no separate install step is required

YAML
1# .circleci/config.yml
2version: 2.1
3
4jobs:
5  schema-check:
6    docker:
7      - image: ghcr.io/apollographql/rover:0.39.1
8        # The image's default entrypoint is `rover`. Override it so CircleCI's
9        # `run:` steps can execute shell commands.
10        entrypoint: ""
11    steps:
12      - checkout
13      - run:
14          name: Subgraph check
15          command: |
16            rover subgraph check $APOLLO_GRAPH_REF \
17              --name $APOLLO_SUBGRAPH_NAME \
18              --schema ./schema.graphql
19
20workflows:
21  ci:
22    jobs:
23      - schema-check:
24          context: apollo # exposes APOLLO_KEY, APOLLO_GRAPH_REF, APOLLO_SUBGRAPH_NAME

Alternative: Linux jobs using the curl installer

If you need to install Rover into an existing executor image (for example, one of the cimg/* images), use the shell installer. CircleCI doesn't persist $PATH between run steps, so append Rover's bin directory to $BASH_ENV, which CircleCI sources at the start of every step:

Bash
1echo 'export PATH=$HOME/.rover/bin:$PATH' >> $BASH_ENV

Full example

YAML
1version: 2.1
2
3jobs:
4  build:
5    docker:
6      - image: cimg/node:15.11.0
7    steps:
8      - run:
9          name: Install
10          command: |
11            curl -sSL https://rover.apollo.dev/nix/v0.39.1 | sh
12            # Persist the PATH change for subsequent steps.
13            echo 'export PATH=$HOME/.rover/bin:$PATH' >> $BASH_ENV
14      - checkout
15      # Only run with `--background` if you have the Apollo Studio GitHub integration enabled.
16      - run: rover graph check my-graph@prod --schema ./schema.graphql --background

Bitbucket Pipelines

Bitbucket Pipelines runs every step inside a container, so you can use the official Rover image directly as the step image.

The following example shows how to:

  • Run rover subgraph check for each commit on all branches

  • Run rover subgraph publish to keep the schema of your main branch synchronized with a base variant (@local in this case)

It expects the following Pipeline Repository Variables to keep the configuration portable across repositories:

  • APOLLO_KEY

  • APOLLO_SUBGRAPH_NAME — the name of the subgraph being checked or published

  • APOLLO_LOCAL_PORT — the port number of the base variant

YAML
1# ./bitbucket-pipelines.yml
2
3definitions:
4  steps:
5    - step: &rover-subgraph-check
6        name: "[Rover] Subgraph Check"
7        image: ghcr.io/apollographql/rover:0.39.1
8        script:
9          - rover subgraph check my-graph@prod
10              --name "$APOLLO_SUBGRAPH_NAME"
11              --schema ./schema.graphql
12
13    - step: &local-publish
14        name: "[Rover] @local publish (sync with main/master)"
15        image: ghcr.io/apollographql/rover:0.39.1
16        script:
17          - rover subgraph publish my-graph@local
18              --name "$APOLLO_SUBGRAPH_NAME"
19              --schema ./schema.graphql
20              --routing-url "http://localhost:$APOLLO_LOCAL_PORT/graphql"
21
22pipelines:
23  default:
24    - step: *rover-subgraph-check
25
26  branches:
27    "{main,master}":
28      - step: *rover-subgraph-check
29      - step: *local-publish

Alternative: install Rover with the shell installer

If you can't pull the Rover image (for example, you're already using a custom build image with other tooling baked in), install Rover with the shell installer and add it to PATH for subsequent commands. Bitbucket Pipelines runs each script: entry in the same shell, so the export PATH=... persists within the step.

YAML
1image: debian:stable-slim
2
3definitions:
4  steps:
5    - step: &rover-subgraph-check
6        name: "[Rover] Subgraph Check"
7        script:
8          - apt-get update && apt-get install -y --no-install-recommends curl ca-certificates
9          - curl -sSL https://rover.apollo.dev/nix/v0.39.1 | sh
10          - export PATH="$HOME/.rover/bin:$PATH"
11          - rover subgraph check my-graph@prod
12              --name "$APOLLO_SUBGRAPH_NAME"
13              --schema ./schema.graphql

Jenkins

If your Jenkins controller has Docker available, run the Rover-using stages inside the official image. The image already contains the Rover binary, so no install step is needed.

Groovy
1pipeline {
2  agent none
3  stages {
4    stage('Rover Check') {
5      agent {
6        docker {
7          image 'ghcr.io/apollographql/rover:0.39.1'
8          // The image's default entrypoint is `rover`. Override it so Jenkins
9          // can run shell steps inside the container.
10          args  '--entrypoint='
11        }
12      }
13      steps {
14        sh '''
15          rover subgraph check "$APOLLO_GRAPH_REF" \
16            --name "$APOLLO_SUBGRAPH_NAME" \
17            --schema "$SCHEMA_PATH"
18        '''
19      }
20    }
21
22    stage('Schema Publish to Dev') {
23      when { expression { env.BRANCH_NAME == 'main' } }
24      agent {
25        docker {
26          image 'ghcr.io/apollographql/rover:0.39.1'
27          args  '--entrypoint='
28        }
29      }
30      steps {
31        sh '''
32          rover subgraph publish "$APOLLO_GRAPH_REF" \
33            --name "$APOLLO_SUBGRAPH_NAME" \
34            --schema "$SCHEMA_PATH"
35        '''
36      }
37    }
38  }
39  environment {
40    APOLLO_KEY = credentials('apollo_key')
41    APOLLO_SUBGRAPH_NAME = 'products'
42    APOLLO_GRAPH_REF = 'ApolloJenkins@dev'
43    SCHEMA_PATH = './graph/schema.graphqls'
44  }
45}

Apollo strongly recommends passing APOLLO_KEY via a Jenkins credential and referencing it with credentials(...), as shown above.

Alternative: install Rover inside a custom build image

If you'd rather bake Rover into your existing build image, use the shell installer and reference the binary by full path so it works across sh steps:

dockerfile
1FROM golang:1.18
2RUN useradd -m rover && echo "rover:rover" | chpasswd
3USER rover
4RUN curl -sSL https://rover.apollo.dev/nix/v0.39.1 | sh

Reference Rover by its full path in pipeline steps (Jenkins doesn't persist $PATH across sh blocks):

Groovy
1sh '$HOME/.rover/bin/rover subgraph check "$APOLLO_GRAPH_REF" --name "$APOLLO_SUBGRAPH_NAME" --schema "$SCHEMA_PATH"'

GitLab

GitLab CI/CD supports a per-job image:, so you can use Rover directly from the official image with no install step:

YAML
1stages:
2  - publish_subgraphs
3
4publish_subgraphs:
5  stage: publish_subgraphs
6  image: ghcr.io/apollographql/rover:0.39.1
7  retry: 1
8  script:
9    - rover subgraph publish "$APOLLO_GRAPH_REF"
10        --name "$APOLLO_SUBGRAPH_NAME"
11        --schema "$SCHEMA_PATH"
12  variables:
13    APOLLO_KEY: $APOLLO_FEDERATION_KEY

Alternative: debian:stable-slim + curl

If you can't pull from ghcr.io or Docker Hub, you can install Rover into a generic Debian image:

YAML
1stages:
2  - publish_subgraphs
3
4publish_subgraphs:
5  stage: publish_subgraphs
6  image: debian:stable-slim
7  retry: 1
8  before_script:
9    - apt-get update && apt-get install curl -y
10  script:
11    - curl -sSL https://rover.apollo.dev/nix/v0.39.1 | sh
12    - export PATH="$HOME/.rover/bin:$PATH"
13    - export APOLLO_KEY=$APOLLO_FEDERATION_KEY
14    - rover subgraph publish "$APOLLO_GRAPH_REF" --name "$APOLLO_SUBGRAPH_NAME" --schema "$SCHEMA_PATH"

Using With npm/npx

If you're running in a Node.js workflow, you can adopt the npm distribution of Rover. This way, you don't need to adjust the PATH to run Rover, and it fits well into your existing workflow.

caution
The npm distribution is provided for convenience in projects that are already in the Node ecosystem. Apollo does not recommend it otherwise, as it exposes your CI environment to npm's surface area of potential supply-chain attacks. Rover's npm installation script has been minimized to reduce that surface, but it still represents nonzero risk. For Node-free pipelines, prefer the Docker image or the Apollo-published GitHub Actions.

You can use Rover by adding it to your package.json dependencies using these instructions and then execute it using npm scripts, similar to other workflows you might already have. If you don't want to install Rover as a dependency, you can run it with npx by using the -p flag:

note
Only run this command with the --background flag if you have the Apollo Studio GitHub integration enabled on your repository.
Bash
1npx -p @apollo/rover rover graph check my-graph@prod --schema=./schema.graphql --background
caution
Invoking Rover directly via npx (without first installing it as a devDependency) bypasses lockfiles — including Rover's own — and is the highest-risk install path in terms of supply-chain exposure. In CI, prefer adding @apollo/rover to your project's devDependencies so the resolved version is captured in your lockfile.