An integration breaks most often when the API behind it changes and nobody on your side chose the change. On November 4, Google gave Compute Engine a way to stop that: dated API versions you can pin. The release also shows something easy to miss, that upgrading an SDK can now upgrade the API behaviour you get. This article explains what changed and how we would pin and upgrade any API an integration depends on.

What Google shipped

Compute Engine's API has had one stable surface, /v1, for more than a decade. Google's announcement calls it "a single, mutable production surface shared by every customer worldwide", which is why changing even a default "carried the risk of breaking existing scripts".

Multi-versioning, now generally available, adds dated snapshots next to /v1. Stable versions arrive quarterly, starting with 2026-09-01, and Google says they "don't receive breaking changes after they're published". Preview versions such as 2026-10-01-preview carry a one-year lifespan. /v1 stays the default when a request names no version, so nothing you run today changes unless you opt in.

You choose a version per request with the X-Goog-Api-Version header or the $apiVersion query parameter. That follows Google's general rule for this scheme, AIP-185: "API requests under IBV must send the API version identifier using either the X-Goog-Api-Version HTTP header or the $apiVersion URL query parameter."

The defaults are what change

The new versions don't just add fields. They change behaviour that existing code may rely on. Google's example: in /v1, an AggregatedList call across all zones defaults returnPartialSuccess to false, so one zone's trouble can fail the whole request. In the dated versions, partial success is on by default.

That is a better default, and it is also a different answer to the same call. Code that assumed a complete list, or that treated any missing zone as an error, would now get a partial list back without failing. Errors change too: the new versions return structured google.rpc.ErrorInfo payloads with a reason, domain and metadata, so code that matched on error text needs to read the structured fields instead.

Your SDK upgrade is now an API upgrade

This is the part that catches teams. Google's table for client libraries says each SDK release "automatically binds to a specific date-based API version while preserving the /v1 package namespace". The import path stays the same and the version under it moves.

So a routine dependency bump, the kind a bot opens every week, can change API behaviour with no change to your code. The same goes for gcloud, which targets "the bundled stable API version", and for the Terraform provider. The version you speak is now a dependency, and it deserves the same care as any other.

How we would pin it

Here is a sketch of how we would call the API directly with the version in one place, so it changes only when someone changes it on purpose.

// One place that says which API version we speak.
export const API_VERSIONS = {
  compute: "2026-09-01",
} as const;

const BASE = "https://compute.googleapis.com/compute/v1";

export async function computeGet(
  path: string,
  token: string,
  version: string = API_VERSIONS.compute,
): Promise<unknown> {
  const res = await fetch(`${BASE}/${path}`, {
    headers: {
      Authorization: `Bearer ${token}`,
      "X-Goog-Api-Version": version,
    },
  });
  if (!res.ok) throw new Error(`${res.status} on ${version}`);
  return res.json();
}

Notice that the version travels with every request and lives in one constant, so a pull request that bumps it is a reviewable event with its own diff. If you use an SDK instead, the equivalent is pinning the library to an exact version and reading its release notes for the API version it binds to.

Before bumping the pin, we would run the requests the integration makes against both versions in staging and compare:

// Same request, current and candidate version, in staging only.
const path = "projects/my-project/aggregated/instances";
const [now, next] = await Promise.all([
  computeGet(path, token, API_VERSIONS.compute),
  computeGet(path, token, "2026-10-01-preview"),
]);
const keys = (o: unknown) => Object.keys(o as object).sort().join();
if (keys(now) !== keys(next)) console.warn("response shape changed");

Notice this checks shape, not values. It is a cheap early warning that tells you where to read the release notes closely. Preview versions are for testing; AIP-185 says they "must not be used for stable releases".

Where this costs you

Pinning means you choose when to upgrade, and that also means you have to. A pin left for years drifts away from security fixes and new defaults you would want. Google says stable versions have "no end-of-support date today", which is generous, but it is a statement about today. Put the upgrade on a calendar, quarterly to match the releases.

If your integration only lists a few instances through gcloud in a script you run by hand, none of this is worth the ceremony. It matters when production code calls the API on its own, on a schedule, without a person watching.

The same discipline applies to every external API a product depends on, AI models included. We wrote about making a model switch a config change and about canaries that notice when a hosted agent changes. A pinned API version is the same idea for infrastructure.

What to remember

  • Compute Engine now has dated, immutable API versions; /v1 stays the default.
  • New versions change defaults, such as partial success on aggregated lists, and error formats.
  • SDK, gcloud and Terraform upgrades can move the API version under you.
  • Keep the version in one place, test the next one in staging, and upgrade on a schedule.

If you are building integrations that have to keep working while the APIs under them move, book a conversation.

Sources