Gateway API Conformance and Portability
“Gateway API is portable” is true in a narrower sense than it first appears, and the difference between the broad reading and the narrow one is where migration projects lose a month. Portability is defined by a conformance programme with named feature sets and published reports, and a configuration is portable exactly to the extent that it uses features every candidate implementation has passed. This page covers how the levels are defined, how to read a conformance report, and how to keep the portable and non-portable parts of your configuration separate on purpose.
Prerequisite concepts
This assumes familiarity with the resource model in Kubernetes Ingress and Gateway API, and it complements gateway selection criteria, which covers the non-API dimensions — operational burden, extensibility model, team skills — that a conformance report deliberately says nothing about.
Three levels, and what each one promises
The third band is not a failure of the specification. Rate limiting and authentication differ so much between products that a single portable schema would either be a lowest common denominator or an unimplementable superset. Keeping them out of the route types is what let the route types stabilise.
Reading a conformance report
Every implementation that claims conformance publishes a machine-readable report per release, listing the profiles it ran and the features it supports.
# excerpt from a published conformance report
apiVersion: gateway.networking.k8s.io/v1
kind: ConformanceReport
implementation:
organization: example-org
project: example-gateway
version: v1.4.2
gatewayAPIVersion: v1.2.1
profiles:
- name: HTTP
core: { result: success, statistics: { passed: 42, failed: 0, skipped: 0 } }
extended:
result: success
supportedFeatures:
- HTTPRouteRequestTimeout
- HTTPRouteMethodMatching
- HTTPRouteResponseHeaderModification
unsupportedFeatures:
- HTTPRouteRequestMirroring # <- the one your canary plan needed
- name: GRPC
core: { result: success }
Three things to check, in order. First, gatewayAPIVersion — a report against an older API version says nothing about fields added since. Second, the unsupportedFeatures list, which is the actionable part and is easier to read than the passed count. Third, whether the profile you care about was run at all: an implementation may be fully conformant for HTTP and not implement GRPCRoute.
Keeping the portable part portable
The practical technique is directory separation, enforced in review. Routes that use only Core and agreed Extended features live in one place; policy attachments live in another; and the split is visible in every pull request.
k8s/
routes/ # portable: HTTPRoute, GRPCRoute, ReferenceGrant
orders-route.yaml
payments-route.yaml
gateways/ # portable: Gateway, listeners, TLS refs
edge-gateway.yaml
policies/ # NOT portable: one subdirectory per implementation
envoy-gateway/
orders-ratelimit.yaml
orders-retry.yaml
Running the upstream conformance suite against your own cluster is the other half, and it is worth doing even when you have no plans to switch implementations: it catches the case where a controller upgrade quietly drops support for an Extended feature you depend on.
# run the upstream suite against the class you actually use
go test ./conformance -run TestConformance \
-args --gateway-class=envoy-gateway \
--supported-features=HTTPRouteRequestTimeout,HTTPRouteMethodMatching
Decision matrix
| Situation | What to do |
|---|---|
| Choosing between two implementations | diff their unsupportedFeatures lists for the profiles you use |
| A feature you need is Extended | confirm support in the report, then pin the version |
| A feature you need is implementation-specific | accept the lock-in explicitly, and isolate it in policies/ |
| Planning a future migration | budget for rewriting policies/ entirely, not for editing it |
| Upgrading a controller | re-run conformance before rolling it to production |
Gotchas and failure signals
An unsupported field may be accepted and ignored rather than rejected, depending on the implementation. The route reports Accepted: True and the behaviour is simply absent — a mirror that never mirrors, a timeout that never fires. Verify behaviour, not status, for anything above Core.
Conformance is per version, not per product. A report for v1.4.2 tells you nothing about v1.5.0, and Extended support has been dropped between minor releases before.
Policy attachment points differ even where the policy is equivalent. One implementation attaches rate limiting to the route, another to the backend, a third to the Gateway. The effective scope differs accordingly, so a “same” policy can apply to more traffic than it did before.
A “supports Gateway API” claim in marketing material is not a report. Ask for the ConformanceReport for the specific release; if there is not one, treat every feature above Core as unverified.
Validation
- The conformance report for your exact controller version is on file
- Every Extended feature in use appears in that report’s
supportedFeatures - Portable routes and implementation-specific policies live in separate directories
- The upstream conformance suite runs in CI against your GatewayClass
- Behaviour of each Extended feature is asserted by a test, not assumed from status
FAQ
What does Core conformance actually guarantee?
That every conformant implementation passed the same upstream test suite for those features, so path and header matching, weighted backends, the standard header modifier and redirects behave identically. A route that uses only Core features can be moved between conformant implementations unchanged. That is a real guarantee, and it is narrower than most teams assume when they hear the word portable.
Why are rate limiting and authentication not in the specification?
Because the products differ too much for one schema to describe them without becoming either a lowest common denominator or an unimplementable superset. Leaving them out as policy attachments is what allowed the route types to stabilise. The trade is explicit: those parts of your configuration are locked to an implementation and should be stored separately so that lock-in is visible.
How do I check whether an implementation supports a feature?
Read the ConformanceReport published for the exact release you run. The unsupportedFeatures list per profile is the actionable part, and it is more useful than the pass count. Also check gatewayAPIVersion — a report against an older API version says nothing about fields added since — and confirm the profile you need, such as GRPC, was run at all.
What happens if I use a field an implementation does not support?
Behaviour varies: some implementations reject the resource, others accept it and silently ignore the field. The second case is the dangerous one, because the route reports Accepted true while the mirror never mirrors or the timeout never fires. For anything above Core, assert the behaviour with a test rather than trusting the status block.
Parent: Kubernetes Ingress & Gateway API
Related
- Kubernetes Ingress & Gateway API — the resource model whose feature levels this page classifies.
- Gateway Selection Criteria — the operational dimensions a conformance report deliberately ignores.
- Kong vs Tyk vs Envoy for Microservices — how three implementations differ once you look past the API surface.