All notable changes to Rover will be documented in this file.
This project adheres to Semantic Versioning.
Important: 1 potentially breaking change below, indicated by ❗ BREAKING ❗
Remove rover cloud commands - @dotdat
rover cloud config fetch, rover cloud config update, and rover cloud config validate have been removed, along with their underlying GraphQL operations.
Add rover auth logout, gated behind the experimental oauth feature flag - @dotdat
rover auth logout revokes the OAuth session stored by rover auth login for the given --profile (or "default") — the access token and, if one was issued, the refresh token (RFC 7009) — then removes the local credential. Revocation is best-effort: if the OAuth server can't be reached, Rover still clears the local credential and warns instead of leaving you stuck "logged in" locally. Only meaningful for profiles logged in via rover auth login; running it against a profile holding a Personal API Key (from rover config auth) errors and points you at rover config delete instead. Only compiled in when built with --features oauth, matching rover auth login.
Show successful build and operation check sections in plain-text check output - fixes #1816
rover subgraph check and rover graph check now show explicit Build Check [PASSED] and Operation Check [PASSED] sections even when no schema changes or operation warnings were found. This makes successful check results visible alongside linter and other check sections.
Fix a flaky lint-report test - @dotdat
rover-client's utf8_points_to_correct_place test could fail depending on whether the NO_COLOR/APOLLO_NO_COLOR environment variables happened to be set in the environment running the test suite, since that changes not just color but the literal report-kind text ("Warning" vs the raw "WARNING" level string). The test now pins both env vars unset for its duration, so it's deterministic regardless of the ambient environment. No user-facing behavior change.
Retry the Check Markdown Links CI job on transient network failures - @dotdat
The Check Markdown Links job now retries up to 3 times if it fails, since transient connection resets to external hosts were occasionally failing the job on a link that was never actually broken. lychee (the link checker) doesn't retry connection-establishment errors regardless of its own retry config, so this is handled at the CI level instead, matching how other flaky steps are already retried in this repo. No user-facing change.
Store profile credentials in the OS keychain instead of a plaintext file - @dotdat
rover config auth now stores each profile's API key in the OS-native credential store (Keychain on macOS, Credential Manager on Windows, the kernel keyring on Linux), falling back to a permission-hardened (0600/0700) JSON file when no native keychain is available — for example, headless Linux/CI, or an unsigned local build on macOS. Existing plaintext $APOLLO_CONFIG_HOME/profiles/<profile>/.sensitive files are transparently migrated the first time they're read, then removed. rover config auth, whoami, list, delete, and clear all behave the same as before, and the APOLLO_KEY environment variable override is unaffected. On some platforms the OS may now prompt for keychain access the first time a credential is read or written in a session. If Rover ever fails to read, write, or delete a credential, it now surfaces a dedicated error, E046, instead of a generic failure.
Add OAuth token storage to the credential model - @dotdat
A profile's stored credential can now be an OAuth access token (with an optional refresh token and expiry), alongside the existing Personal API Key, in the same OS-native secret store added above. Requests made with an OAuth credential now send Authorization: Bearer <token> instead of x-api-key. This is internal plumbing — see rover auth login below for the command that now writes one.
Add rover auth login, gated behind an experimental oauth feature flag - @dotdat
rover auth login authenticates via OAuth 2.0 (PKCE authorization-code flow): it opens your browser, completes the login against Apollo's Identity service, and stores the resulting session the same way rover config auth stores a Personal API Key (--profile <name> works the same way). Only compiled in when built with --features oauth — off by default, and not part of any released binary yet. Uses a static, pre-registered OAuth client (one per environment) rather than registering a new client per install; the top-level --oauth-authorization-url/--oauth-token-url/--oauth-client-id flags override the defaults (Apollo's production OAuth server and its registered rover client) for testing against other environments. These are top-level flags, not ones scoped to auth login, so they'll also apply to any future command that needs to refresh an OAuth token. The authorization URL is always printed to stderr regardless of whether a browser opens; pass --no-open to skip the open attempt entirely — useful over SSH or in any environment without a browser.
Add rover auth whoami, gated behind the same experimental oauth feature flag - @dotdat
rover auth whoami displays the identity of the currently authenticated profile. For a profile logged in via rover auth login, it queries the OAuth identity provider's /userinfo endpoint directly and shows the account's name, email, and user ID; for a profile still using a legacy Personal API Key (via rover config auth or APOLLO_KEY), it falls back to the same Apollo Studio lookup rover config whoami already does. rover config whoami itself is unchanged aside from a new stderr note pointing at rover auth whoami going forward. Both lookups now go through a tower retry/timeout policy (bounded per-attempt timeout, exponential-backoff retry on transient failures) — the OAuth REST call didn't have either before, so a hung connection or a flaky identity provider could previously leave the command stuck indefinitely. The new --oauth-whoami-url flag overrides the /userinfo endpoint the same way the existing OAuth endpoint flags do.
Add OAuth 2.0 client credentials authentication for CI, gated behind the experimental oauth feature flag - @dotdat
If APOLLO_CLIENT_ID and APOLLO_CLIENT_SECRET are both set, Rover now exchanges them for an access token via the OAuth 2.0 client credentials grant (RFC 6749 §4.4) and uses it exactly as it would an APOLLO_KEY — no new subcommand, no stored session, no other behavior change. This is meant for CI/machine-to-machine use where the interactive, browser-based rover auth login isn't an option. Precedence is unambiguous: APOLLO_KEY still always wins; if it's unset and both client-credentials env vars are present, the exchanged token is used instead; otherwise Rover falls back to whatever a stored profile already resolves to, unchanged. Setting only one of APOLLO_CLIENT_ID/APOLLO_CLIENT_SECRET is treated as a configuration error rather than silently falling through to a stored profile. The exchange reuses the same OAuth token endpoint rover auth login does (override with --oauth-token-url). Only compiled in when built with --features oauth, matching rover auth login/logout/whoami.
Important: 1 potentially breaking change below, indicated by ❗ BREAKING ❗
graph introspect --format json now returns GraphQL introspection JSON - @smyrick PR #3440
rover graph introspect with --format json now puts the schema as a GraphQL introspection object ({ "__schema": ... }) under data.introspection_response instead of an SDL string. Default plain output remains SDL. This is a behavior change for existing --format json consumers: traverse data.introspection_response to get the introspection object (for example, jq '.data.introspection_response'). No field or value transformation is needed beyond envelope traversal.
Add rover supergraph config expand to preview an expanded supergraph config - @SharkBaitDLS PR #3447 fixes #1579
rover supergraph config expand --config ./supergraph.yaml prints your supergraph configuration file with all variable references (e.g. ${env.PRODUCTS_URL} and ${file.path}) expanded. This makes it easy to confirm what Rover actually resolves your config to before a composition run. Use --format json to get the expanded config under an expanded_config field.
Add --changelog-message to graph publish and subgraph publish - @SharkBaitDLS PR #3398 fixes #1884 #292
rover graph publish and rover subgraph publish now accept --changelog-message <MESSAGE> to attach a note to the publish in the Studio schema changelog. The publish output has also been enriched: graph publish now reports the schema hash and total named type count and subgraph publish now includes the resulting supergraph composition hash when one is available.
Add rover dev --supergraph-output to control the output of the composed supergraph - @SharkBaitDLS PR #3383 fixes #1864
rover dev can now write the supergraph schema it composes to a path of your choosing and keep it updated on every recomposition, e.g. rover dev --supergraph-output build/supergraph.graphql. Previously the composed supergraph only lived in a temp file, and the global --output/-o flag (which controls a command's own CLI output, not its artifacts) appeared to be silently ignored by dev. The global --output help text now clarifies that distinction.
Add rover graph-artifact tag command - @zw428 PR #3282
Adds the rover graph-artifact tag command for Graph Artifact tagging.
Add rover persisted-queries generate command - @dotdat PR #3481
Scans GraphQL operation files and generates a persisted query manifest, written to a file (--manifest-path) or stdout. Supports --include/--exclude glob filtering and a configurable --root-dir.
Add --check flag to the subgraph-publish GitHub Action - @SharkBaitDLS PR #3375
Add APOLLO_ROVER_SKIP_UPDATE to disable all auto-updating at once - @SharkBaitDLS PR #3378 fixes #1892
Setting the APOLLO_ROVER_SKIP_UPDATE environment variable (to 1 or true) opts out of all of Rover's auto-updating in a single switch: it skips both the rover self-update check (the --skip-update-check flag) and the supergraph/router plugin auto-updates (the --skip-update flag), so on-the-fly plugin resolution uses an already-installed plugin instead of contacting the registry. This is aimed at tightly-controlled monorepo/CI setups that want plugin versions lockstep with CI and prod. The explicit rover install command still installs as requested.
Include error cause detail in --format json output - @SharkBaitDLS PR#3408 fixes #1320
When a command fails, its JSON output now includes a causes array carrying the same Caused by: detail that plain-text output already shows, outermost cause first.
Install plugins without relying on a writable system temp directory - @SharkBaitDLS PR #3385 fixes #1422
Rover now extracts downloaded supergraph/router plugin tarballs inside its own install directory rather than the system temp dir (TMPDIR//tmp), so installations can succeed on read-only filesystems.
Return a clear error when composition produces no output - @SharkBaitDLS PR #3384 fixes #1904
Fall back to an installed plugin when the registry is unreachable - @SharkBaitDLS PR #3362 fixes #1791 #1808
When Rover needs the latest supergraph or router plugin but can't reach the plugin registry (an outage, a network blip, or simply being offline), it now falls back to the newest compatible plugin already installed in ~/.rover/bin with a warning instead of failing outright. Exact version pins still return an error.
Extend the timeout for plugin downloads - @SharkBaitDLS PR #3358 #3386 fixes #1583 #1867
Plugin downloads no longer inherit the 30s default that bounds API requests. With --client-timeout unset, downloads get a 300s default timeout (plus a 30s connection timeout so a genuinely-offline run still fails fast). When --client-timeout is provided, it still applies to downloads as before.
Read UTF-16 (and BOM-prefixed) schema files - @SharkBaitDLS PR #3351 fixes #653
Fs::read_file now detects a leading byte-order mark and transcodes the file to UTF-8, so schemas saved as UTF-16 — most commonly produced by Windows PowerShell > redirects, e.g. rover graph introspect ... > schema.gql — are read instead of failing with "stream did not contain valid UTF-8". A UTF-8 BOM is stripped; files with no recognized BOM are still read as UTF-8 (preserving prior behavior), and malformed input surfaces an error rather than being silently replaced. Decoding is handled by encoding_rs.
Restore the "pin your federation version" warning on supergraph compose - @SharkBaitDLS PR #3347
rover supergraph compose again warns when federation_version is not pinned to an exact version, reinstating the documented notice that future versions will require one. This nudge was added in #1524 and inadvertently dropped in v0.27.2 (#2411) during the supergraph-config resolution rewrite; composing against a floating 1/2 (or omitting the key) now once again warns and recommends pinning, to avoid pulling in breaking changes when a new federation release ships. rover dev and the language server remain silent. Fixes #1510.
Report a clearer error when schema-check polling fails on large schemas - @SharkBaitDLS PR #3349
Centralizes the poll loop between graph/subgraph check, and surfaces a more helpful error when a check likely failed because the schema was too large to download in time. Relates to #1383.
cargo-npm, removing the postinstall script - @dotdat PR #3430cargo npm generate invocation in the release workflow - @dotdat PR #3492keyring-core (keyring 4.0) - @SharkBaitDLS PR #3370Add rover schema search subcommand - @dotdat PR #3315
Wires the new rover schema search FILE TERMS... subcommand on top of the ParsedSchema::search engine added in PR #3262. Accept SDL from a file (or from stdin when FILE is -), render results as text or JSON via the standard CliOutput plumbing, and support --limit/-n and --include-deprecated.
Preserve auth and other reqwest helpers in the retry tower layer - @SharkBaitDLS PR #3327 fixes #3326
Rebuilds requests through reqwest::RequestBuilder inside the retry tower layer so the builder's helper logic (which extracts auth into headers, among other things) is preserved on retried requests. Previously the layer used reqwest::Request::try_from, which silently dropped those helpers. Also restricts retries to retriable HTTP status codes and skip gzip-decoding error responses so the underlying failure surfaces instead of manifesting as a hang.
Rewrite graph introspect to use apollo-compiler - @SharkBaitDLS PR #3317 fixes #3312
Moves graph introspect off the deprecated apollo-encoder crate and onto apollo-compiler to pick up upstream SDL-encoding fixes that Rover had been missing.
Batch supergraph.yaml subgraph changes on hot reload - @SharkBaitDLS PR #3304
Applies all subgraph additions and removals from a single supergraph.yaml edit as one batch before recomposing in rover dev. Previously each change was processed individually, so removing a subgraph whose fields were referenced via @external produced an intermediate composition failure that persisted as the final state without recovering.
Preserve --graph-ref subgraphs across hot reloads - @SharkBaitDLS PR #3288
Re-merges remote --graph-ref subgraphs on every supergraph.yaml reload when rover dev is run with both --graph-ref and a local supergraph file. Previously the watcher only re-read the YAML and dropped the graph-ref-only subgraphs that had been merged in at startup.
Fix release tagging workflow - @SharkBaitDLS PR #3309
Switches the release "refs exist" check to the exact-match GitHub tag API. Previously it used a fuzzy-matching API that incorrectly no-op'd when prior release-candidate tags existed. Also restores the original workflow names to preserve Marketplace URLs and SEO.
Retry artifact uploads in CI - @dotdat PR #3325
Adds retries to actions/upload-artifact so transient network failures during CI uploads no longer fail builds.
Drop unused variant-name querying - @sirdodger PR #3320
Removes the unused variants field from the graph query to improve performance for graphs with many variants.
Run cargo +nightly fmt --all at the end of mise run prep - @dotdat PR #3311
Add Docker image information to CI docs - @SharkBaitDLS PR #3318
Documents the published Docker images in the CI/CD docs and aligns action names with the links already used on the docs site.
Add rover client extract command - @dotdat PR #3223, #3224, #3225
New rover client extract command pulls GraphQL operations out of client code. Includes the core extraction logic, CLI wiring, and integration tests.
Add rover client check command - @dotdat PR #3120
New rover client check subcommand for validating client operations against a schema.
Add rover schema search - @dotdat PR #3262
New subcommand under rover schema for searching schema contents.
Add --check flag to rover graph publish - @joshuaoshields95 PR #3203
Runs graph check and graph publish as a single unit when --check is passed.
Add --use-example-schema flag to subgraph publish - @samaanghani PR #3218
Allows publishing a placeholder schema without needing to provide your own schema file. This is useful for setting up your graph structure before your actual schemas are ready. The placeholder schema is type Query { helloWorld: String } with a routing URL of https://example.com.
Respect --insecure-accept-invalid-certs in rover init --mcp - @dotdat PR #3234
rover init --mcp now honors --insecure-accept-invalid-certs when fetching templates.
Port axios no-proxy behavior - @SharkBaitDLS PR #3270
Restores no_proxy / NO_PROXY handling that was previously provided by axios before its removal in 0.38.0.
Fix path and formatting issues in client check/client extract - @dotdat PR #3285
Use --root-dir in client check fixture tests for cross-platform compatibility - @samaanghani PR #3219
Don't run the automated update check in Docker - @SharkBaitDLS PR #3245
Skips the rover version-update check when running inside a container so Docker users don't see spurious update prompts.
Workaround NPM 11 installation bug - @SharkBaitDLS PR #3230
Add canonical GitHub Actions for install / subgraph / persisted queries - @SharkBaitDLS PR #3264, #3269, #3278, #3279, #3280
New companion actions under apollographql-gh-actions/* for installing rover and wrapping common subgraph and persisted-queries subcommands.
Bump apollo-language-server to 0.8.0 - PR #3251
Restore retry-until-ready behavior for unavailable subgraphs - @dmallare PR #3187
rover dev would continue polling unavailable subgraphs until they came online.axios, axios-proxy-builder and console.table and introduces undici as a dependency. It also pins detect-libc to a fixed version with no further dependencies.rover install command - PR #3022
docs/source/commands/install.mdx covering installing Rover and plugins (supergraph, router, apollo-mcp-server) with --plugin, options (--force, --elv2-license), and navigation updates. The install command is now visible in rover --help.rover dev - @DaleSeo, PR #2784Remove claude_desktop_config.json from MCP template and update "Next Steps" UX - @gocamille, #2746 fixes apollographql/rover-init-starters#84
Updates the MCP template to be more flexible and AI-client agnostic. Removes the prescriptive claude_desktop_config.json file and provides more generic "Next Steps" guidance for connecting any AI client to the generated MCP server.
Remove mcp-claude shortlink - @gocamille, #2747
Removes the Claude Desktop-specific shortlink to align with the more flexible, AI-client agnostic approach to MCP server setup.
--mcp flag to rover init for Model Context Protocol support - @camillelawrence PR #2731
rover init --mcp. This enables two flows: creating new graphs with MCP server capabilities, or augmenting existing projects with MCP tooling.--mcp-collection option for rover dev - @Jephuff PR #2636rover init - @sanchezdale PR #2630
init were set to default to federation 2.10. Now, init sets the default to the federation version defined in the selected starter template.apollographql/federation-rs to v2.11.0 - PR #2627Log cause of introspection error - @pubmodmatt PR #2615
Introspection failures in rover dev were not logging the underlying cause of the failure. This has been fixed to help with debugging introspection problems.
eslint to v9.28.0 - PR #2616zip to v4 - PR #2618rand_regex to v0.18.1 - PR #2606slackapi/slack-github-action action to v2.1.0 - PR #2584duct to v1 - PR #2586npm to v11 - PR #2547quay.io/pypa/manylinux2014_x86_64 docker tag to v2025 - PR #2548Use the Streamable HTTP transport for MCP - @pubmodmatt PR #2607
rover dev --mcp will now use the Streamable HTTP transport instead of SSE. Specify the --mcp-port and/or --mcp-address options to rover dev --mcp to override the default values. The --mcp-sse-port and --mcp-sse-address options still work, but will configure the port and address for Streamable HTTP. Users should migrate to the new option names.
--mcp-directory was optional, but rover dev failed if it was not specified--mcp-sse-address to set the bind address for the MCP server started by rover devERROR or UNKNOWNrover dev would exit but leave the other process runningrover init will now emit the correct commands for Windows PowerShell - @sanchezdale PR #2595Add mcp to rover dev - @Jephuff, @pubmodmatt PR #2591
This release adds the ability to run the Apollo MCP Server in addition to the Apollo Router when running rover dev. Specify the --mcp option to start the MCP server. Additional options are provided to configure the MCP server. Use rover dev --help for details.
Add support for templates in the rover init command
This adds support for templates in the rover init command. You can now select a template to use when creating a new graph!
init flag to default features - @tayrriblestart_point_file to specify what file to use in output - @sanchezdalepq publish into docs - @lleadbetrover init resources - @Meschreiberactions/checkout@v4 in GitHub Actions example workflows - @DaleSeoAdding new command rover init
New rover init command to help set up a new project. It walks you through creating a graph, setting up files, and getting GraphOS credentials.
More information:
init flow when duplicate graph ID is providedrover_std librarydev command's descriptioninitconfiguring slug to docs link listinit commandinit Command with TypeState Pattern