Rover CLI
npx @buildinternet/releases get rover-clinpx @buildinternet/releases get rover-cliAll notable changes to Rover will be documented in this file.
This project adheres to Semantic Versioning.
Important: 3 potentially breaking changes below, indicated by ❗ BREAKING ❗
rover subgraph check's JSON downstream task changes shape, bumping json_version to "3" - @dotdat
The downstream task's blocking_variants: [String] field is replaced by variants, a list of per-contract-variant results (graph_id, variant_name, blocking, fails_upstream_workflow, status) instead of just the names of variants blocking the check. json_version in the response envelope moves from "2" to "3" to reflect the shape change. rover graph check shares the same response envelope and also moves to "3", though its payload is unchanged for now. Text output changes too: a downstream check summary now always renders whenever a downstream task ran, even when nothing is blocking — "No contract variants configured for this graph." or "Checked N contract variants[, all passed]." — instead of staying silent unless something was blocking.
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.
Remove Federation 1 support - @dotdat
Rover no longer supports Federation 1. rover supergraph compose, rover dev, rover lsp, rover connector, and rover install --plugin supergraph@<version> now reject any Federation 1 version (for example federation_version: 1 in supergraph.yaml, or latest-0/an exact 0.x version for the plugin installer) with an error pointing at the Federation 2 migration guide. rover init no longer maps a template's federation version to a Federation 1 build pipeline track.
Add --no-browser to rover auth login, gated behind the experimental oauth feature flag - @dotdat
rover auth login --no-browser uses the OAuth 2.0 Device Authorization Grant (RFC 8628) instead of the local browser/redirect-server flow: it prints a verification URL and code to enter from any device, then polls until you approve the request, for headless or browser-less environments. Ignores --no-open, since there's no local browser step to skip. The device authorization endpoint can be overridden with --oauth-device-authorization-url, matching the other OAuth endpoint overrides.
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.
Print a one-time startup notice when rover dev runs with no GraphOS credentials - @SharkBaitDLS
rover dev has always been able to compose and run a local router session with no API key, graph ref, or offline license — but running it that way gave no confirmation that this was expected, intentional behavior rather than a misconfiguration. It now prints Running without GraphOS credentials. GraphOS Router Enterprise features and @connect are disabled. Pass --graph-ref, set APOLLO_KEY/APOLLO_GRAPH_REF, or pass --license to enable them. once at startup, but only when nothing else already explained the gap (e.g. a --graph-ref or non-default --profile that couldn't resolve credentials still gets its existing, more specific warning instead).
Add rover contract preview - @sirdodger
rover contract preview previews a contract by applying include/exclude/hide-unreachable-types filters to a graph variant's current composed schema, without publishing a contract variant. It runs asynchronously on the server; by default Rover polls until the build completes (or APOLLO_CHECKS_TIMEOUT_SECONDS elapses), or pass --async to just start the build and check on it later with --build-id. Exits non-zero if composition or filtering fails.
Add rover subgraph preview - @sirdodger
rover subgraph preview composes a preview supergraph from hypothetical subgraph changes described by a --subgraph-changes YAML file (add/update a subgraph's schema or routing URL, or mark one remove: true), with optional include/exclude/hide-unreachable-types contract filters, without publishing anything. It runs asynchronously on the server; by default Rover polls until the build completes (or APOLLO_CHECKS_TIMEOUT_SECONDS elapses), or pass --async to just start the build and check on it later with --build-id. Exits non-zero if composition or filtering fails.
rover subgraph delete's pre-confirmation build-error check now runs through this same async preview path instead of a synchronous dry-run mutation, avoiding a long-held server connection (and its timeout risk) while previewing the deletion of a subgraph from a large supergraph.
Report contract variant visibility on rover graph check - @dotdat
rover graph check now reports a downstream check summary for a graph's contract variants, in both text and JSON: how many were checked and their pass/fail breakdown, not just the names of variants that are blocking (previously, graph check reported nothing about contract variants at all). A blocking downstream contract failure now also makes graph check exit non-zero, matching subgraph check's existing behavior.
rover graph publish polls a triggered launch to completion - @dotdat
graph publish now waits for the launch it triggers (and any downstream contract-variant launches) to finish before returning, and --format json gains launch_url, launch_status, launch_superseded, and downstream_launches fields reflecting the outcome. Text/stderr output doesn't report on them yet — that's a following change in this stack.
Report triggered downstream contract-variant launches on rover graph publish - @dotdat
rover graph publish now reports which contract variants had a downstream launch triggered by the publish, with links to each — in text ("Triggered downstream launches for N contract variant(s): ...", printed to stderr) and as a downstream_launches JSON array alongside a launch_url field. Rover polls the publish's launch (and its downstream launches) to completion before reporting success, and fails the publish if the launch itself or any downstream launch didn't complete successfully. Nothing new prints when the publish triggered no downstream launches. stdout is unchanged for now (still just the schema hash on success) — a printed note warns that a future version will move this report into stdout, and points scripts that only need the hash at --format json's .data.api_schema_hash. Note: like other Studio launch data fetched after the fact, this can race a concurrent publish to the same variant — a known limitation, not solved here.
rover subgraph publish polls a triggered launch to completion - @dotdat
subgraph publish now waits (bounded by --checks-timeout-seconds/APOLLO_CHECKS_TIMEOUT_SECONDS) for the launch it triggers (and any downstream contract-variant launches) to finish before returning, and --format json gains launch_status, launch_superseded, and downstream_launches fields reflecting the outcome.
Report triggered downstream contract-variant launches on rover subgraph publish - @dotdat
rover subgraph publish now reports which contract variants had a downstream launch triggered by the publish, with a link, in text (printed to stderr) and JSON. Fails the publish if the launch itself or any downstream launch didn't complete successfully.
rover supergraph compose and rover connector report which plugin they used - @SharkBaitDLS
Every run now prints one stderr line per plugin it resolved — name, exact version, and whether it was downloaded, already installed, or a fallback — even on cached runs, which previously printed nothing, e.g. Using the `supergraph` plugin v2.9.3 (downloaded).. rover dev and rover lsp will report the same information in a following change in this stack.
Composition and related errors no longer print their cause twice - @SharkBaitDLS
A number of error types (supergraph compose's Federation Version/binary-install/subgraph-resolution errors, the LSP's composition-pipeline error, the router config address parser, and several errors in rover-client, rover-http, rover-graphql, and rover-storage) embedded their underlying cause's message directly in their own text while also registering that same cause as the error's source. When such an error surfaced through Rover's normal error-chain rendering, this produced the same message twice — once inline, once again under "Caused by:". These errors now describe only their own context; the cause still renders, exactly once, in the "Caused by:" section.
Some of these errors also reach users through call sites that print an error directly rather than walking its chain — rover dev's composition output, the language server's diagnostics, and a couple of credential-store warnings. Those now render the full chain explicitly, so the cause is still shown there rather than being dropped along with the duplicate.
Stop warning that a floating federation_version will become an error - @SharkBaitDLS
rover supergraph compose warned that "future versions ... will fail without an exact federation version". It now describes the actual risk of leaving the version floating: each run composes with whatever released most recently, which can change your supergraph schema or outrun your router. The nudge to pin is unchanged, and rover dev and the language server stay silent as before.
rover graph publish/subgraph publish --format json keep the publish response when a triggered launch fails - @dotdat
A failed launch or downstream contract-variant launch used to make either command return a bare error, discarding the whole response — --format json reported "data": null with no error.code to match on, even though the schema publish itself had succeeded. Both now surface this as RoverClientError::PublishLaunchFailure (E047), so data still carries the full publish response (api_schema_hash, launch_status, launch_superseded, downstream_launches, and so on) alongside the coded error.
rover connector test now exits non-zero and reports success: false when the suite fails - @benjamn
A failing connector test suite makes the supergraph test-connectors binary exit 1, but Rover's shared execution helper whitelisted exit 1 as success (correct for compose, where it means "composed with build errors"), so Rover reported success and exited 0 on failing runs — and --format json told machines {"data": {"output": "", "success": true}}. The exit-code policy is now per-subcommand, and test-connectors treats only exit 0 as success, matching the exit-code contract documented in the Apollo-Connectors-CLI README.
rover subgraph check now fails on an actually-failed blocking downstream contract check, even when the overall workflow status hasn't caught up - @dotdat
subgraph check's exit code only ever looked at the overall check-workflow status, never at the downstream task's per-variant data, so a blocking downstream contract check that had genuinely failed could be missed entirely if Studio's aggregate status hadn't caught up yet — the command would report success and exit zero. It now escalates to a failure whenever any downstream variant is an actual blocking failure, the same DownstreamCheckResponse::has_blocking_failure gate graph check already uses, bringing subgraph check's exit code and JSON downstream.task_status in line with graph check's existing behavior. Supersedes the stale, unmerged #3377.
Register the device-code grant type for rover auth login --no-browser's OAuth client - @dotdat
Every OAuth client provisioned via cargo xtask register-oauth-client (for both staging and prod) was registered with only the authorization_code grant type, never urn:ietf:params:oauth:grant-type:device_code - so rover auth login --no-browser always failed at the very first step, with the server rejecting the device-authorization request as unsupported_grant_type
Surface the underlying GraphQL errors when a response has no data field - @sirdodger
Requests that returned GraphQL errors alongside a null/missing data field previously showed a generic message instead of the actual error text. GraphQLServiceError::NoData now maps to the underlying errors (joined by newline) when there are any, falling back to the generic "No data field provided" message only when the response truly carried no errors either.
Restore the --license flag on rover dev - @SharkBaitDLS
rover dev --license <path> let you start a local router session with an offline enterprise license, no GraphOS credentials or network calls required. The flag survived a rover dev internals rewrite, and kept appearing in --help and linking to real router docs, but the code that actually read it was deleted along the way — passing --license silently did nothing. It's wired back up now, forwarded to the router the same way it always was, independent of whatever --graph-ref/APOLLO_KEY credentials are also resolved.
Fail immediately on errors that a retry can't fix - @SharkBaitDLS
A rejected API key, a permissions failure, or a bad endpoint URL used to be retried repeatedly for the full --client-timeout (30 seconds by default) before Rover said anything, so a mistyped key or URL took the better part of a minute to report. These now fail as soon as the answer comes back. Rate limits and server errors are still retried, since those do clear up on their own.
Stop reporting a malformed API key when the format is fine - @SharkBaitDLS fixes #1171
A revoked, expired, or unrecognized API key used to fail with error[E014]: The API key you provided is malformed., sending you off to fix a format that was already correct. E014 is now reserved for keys that genuinely aren't shaped like user:my-username:secretkey or service:graph-id:secretkey. Anything else the registry turns down reports error[E013]: The registry did not recognize the provided API key, so you're pointed at whether the key is still valid rather than at how it looks. Introspecting your own subgraph no longer blames your Apollo credentials either.
Fix interactive confirmation prompts not waiting for input when stdout (but not stdin) is redirected - fixes #1455
y/N confirmation prompts (the ELv2 license acceptance prompt, rover graph delete/rover subgraph delete confirmations) checked whether stdout was attached to a terminal before reading an answer. Redirecting stdout while leaving stdin interactive made the prompt print, then immediately read an empty answer instead of waiting for input, defaulting to "no" and erroring out. Prompts now read from stdin directly, gated on stdin's own terminal status.
Catch a bad API key while rover init is still asking for one - @SharkBaitDLS
rover init only checked that a pasted key began with user:, so a truncated key was accepted and saved, then failed on the next request. It now checks the whole key, and says which thing is wrong: a key that isn't shaped like a key at all asks you for a valid one, while a graph key gets the guidance for clearing APOLLO_KEY and stored profiles. A key pasted with a trailing newline is no longer saved with it. rover init also stops reusing an APOLLO_KEY that looks like a graph key but is truncated.
Report an API key the registry refuses outright, not just one it names in a response - @SharkBaitDLS
Commands on Rover's newer request stack could only recognize a rejected API key when the registry said so in the body of its response. When it refused the request outright instead, the failure surfaced as an internal error rather than E013/E014. Those commands now report a refused request as E013/E014 too, matching the rest of Rover.
Report a rejected API key as E013 instead of an internal error - @SharkBaitDLS part of #1171
When the registry turned down an API key, several commands reported it as an internal error carrying no error code at all, while others reported E013 — so the same key gave different diagnostics depending on which command you ran. rover graph fetch, rover client check, rover graph-artifact list-tags, and remote subgraph fetching during composition now report it the same way as the rest. rover graph validate-operations and rover subgraph fetch-all continue to report E033 where a rejection could equally mean your key is valid but lacks permission for that operation. Failures that aren't about your credentials are unaffected.
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.
Report a rejected API key as E013/E014 even when the registry responds 200 OK - @dotdat
When the registry rejects a key by returning HTTP 200 with "data": null and a body-level "Invalid credentials" error (rather than an HTTP 401/406), Rover used to report a generic, undifferentiated error: No data field provided instead of the usual E013/E014. The credential-rejection check only ever looked at a nested extensions.response field on each GraphQL error, never the error's own top-level message, which is where this particular response places the context. The check now looks at each error's top-level message, and runs regardless of whether data is present, null, or omitted. A related gap is fixed alongside it: rover graph fetch and rover graph-artifact list-tags now also check whether the rejected key was malformed (e.g. missing colons) before settling on E013, matching the check every other command already applied - so a key that was never validly shaped reports E014 there too, not just E013.
Stop baking "N operation(s)" text into a rover-client type - @dotdat
Removes pluralization print concerns from rover-client and hoists them into the binary
Move check-workflow text rendering out of rover-client - @dotdat
CheckWorkflowResponse UI concerns are moved higher up to the CLI binary. Its hand-rolled "N item(s)" pluralization now uses the pluralizer crate.
Switch graph publish/subgraph publish from raw eprintln! to rover-print - @dotdat
Both commands now print their stderr status lines through rover-print's Print/PrintExt trait via an injected printer, matching the pattern already used by contract preview/subgraph preview. No user-facing output change.
latest_plugin_versions.json migration - @dotdat
Rover's bundled copy of latest_plugin_versions.json has been deleted and its behavior has been moved into the Orbiter service, its only real consumer.
Add an RFC 8628 OAuth device authorization grant implementation to rover-auth - @dotdat
Adds DeviceAuthorizationFlow to rover-auth's oauth2 module: requesting a device code, and polling the token endpoint until the user approves the request from another device. Not yet wired up to any command; a follow-up PR adds rover auth login --no-browser.
Replace GitHub reqwest client with apollo-http-client - @SharkBaitDLS
Simplify the rover-print API to stop propagating write errors - @dotdat
Print/PrintExt methods (print, print_line, infoln, warnln, errln, successln) no longer return std::io::Result<()>. A failed terminal write now records a best-effort tracing::error! diagnostic (visible when running with --log) instead of being propagated; most callers previously discarded the error with let _ = ..., so this is a no-op for them. A few call sites (rover config auth, rover config whoami, rover persisted-queries generate) previously used ? and would fail the whole command on a print error — those now continue and succeed instead, which is an intentional, if obscure, 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