# Gateway API vs Ingress: Why Modern Kubernetes Traffic Management Uses Attachment, Not Annotations Source: https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html Published: 2026-03-16T10:00:00.000-07:00 Updated: 2026-10-13T00:08:13.998-07:00 Author: Unknown Topics: devops, gateway-api, ingress, kubernetes, Networking, traffic-management Ingress is still valid, but it stopped evolving. Gateway API gives Kubernetes teams a cleaner resource model for shared edge infrastructure, richer routing, and safer multi-namespace ownership. ## TL;DR [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-1) Gateway API is the practical successor to Kubernetes Ingress for teams that need more than host and path routing. Instead of collapsing infrastructure, TLS, and application routing into one resource plus controller-specific annotations, it separates concerns across GatewayClass, Gateway, and HTTPRoute. That gives platform teams explicit entry points, application teams structured routing rules, and both sides a safer attachment model for shared gateways. The result is better portability, clearer ownership, richer HTTP routing, and a migration path that does not require an all-at-once cutover. ![Generated diagram comparing annotation-heavy Ingress with the Gateway API attachment model using GatewayClass, Gateway, and HTTPRoute.](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDYzMCIgd2lkdGg9IjEyMDAiIGhlaWdodD0iNjMwIiByb2xlPSJpbWciIGFyaWEtbGFiZWxsZWRieT0idGl0bGUgZGVzYyIgc3R5bGU9ImRpc3BsYXk6YmxvY2s7d2lkdGg6MTAwJTtoZWlnaHQ6YXV0bzsiPgogIDx0aXRsZSBpZD0idGl0bGUiPkdhdGV3YXkgQVBJIHZlcnN1cyBJbmdyZXNzIHRyYWZmaWMgbW9kZWw8L3RpdGxlPgogIDxkZXNjIGlkPSJkZXNjIj5BIGdlbmVyYXRlZCBkaWFncmFtIGNvbXBhcmluZyBhbm5vdGF0aW9uLWhlYXZ5IEluZ3Jlc3MgcmVzb3VyY2VzIHdpdGggdGhlIEdhdGV3YXkgQVBJIGF0dGFjaG1lbnQgbW9kZWwgdXNpbmcgR2F0ZXdheUNsYXNzLCBHYXRld2F5LCBhbmQgSFRUUFJvdXRlLjwvZGVzYz4KICA8ZGVmcz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iYmciIHgxPSIwIiB4Mj0iMSIgeTE9IjAiIHkyPSIxIj48c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjMTExODI3Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjMWQ0ZWQ4Ii8+PC9saW5lYXJHcmFkaWVudD4KICAgIDxmaWx0ZXIgaWQ9InNoYWRvdyIgeD0iLTIwJSIgeT0iLTIwJSIgd2lkdGg9IjE0MCUiIGhlaWdodD0iMTQwJSI+PGZlRHJvcFNoYWRvdyBkeD0iMCIgZHk9IjE2IiBzdGREZXZpYXRpb249IjE4IiBmbG9vZC1jb2xvcj0iIzAyMDYxNyIgZmxvb2Qtb3BhY2l0eT0iMC4yMiIvPjwvZmlsdGVyPgogIDwvZGVmcz4KICA8cmVjdCB3aWR0aD0iMTIwMCIgaGVpZ2h0PSI2MzAiIHJ4PSIyOCIgZmlsbD0idXJsKCNiZykiLz4KICA8dGV4dCB4PSI3NCIgeT0iOTIiIGZpbGw9IiNiZmRiZmUiIGZvbnQtZmFtaWx5PSJTZWdvZSBVSSwgQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjIiIGZvbnQtd2VpZ2h0PSI3MDAiIGxldHRlci1zcGFjaW5nPSI0Ij5LVUJFUk5FVEVTIFRSQUZGSUMgTUFOQUdFTUVOVDwvdGV4dD4KICA8dGV4dCB4PSI3NCIgeT0iMTUyIiBmaWxsPSIjZmZmZmZmIiBmb250LWZhbWlseT0iU2Vnb2UgVUksIEFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjUwIiBmb250LXdlaWdodD0iODAwIj5HYXRld2F5IEFQSSB2cyBJbmdyZXNzPC90ZXh0PgogIDx0ZXh0IHg9Ijc0IiB5PSIyMDYiIGZpbGw9IiNkYmVhZmUiIGZvbnQtZmFtaWx5PSJTZWdvZSBVSSwgQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjQiPlRoZSBkaWZmZXJlbmNlIGlzIG5vdCBqdXN0IHJvdXRpbmcgZmVhdHVyZXMuIEl0IGlzIHdobyBvd25zIGF0dGFjaG1lbnQsIGxpc3RlbmVycywgYW5kIGNyb3NzLW5hbWVzcGFjZSBhY2Nlc3MuPC90ZXh0PgogIDxnIGZpbHRlcj0idXJsKCNzaGFkb3cpIj4KICAgIDxyZWN0IHg9IjcyIiB5PSIyNjgiIHdpZHRoPSI0ODQiIGhlaWdodD0iMjg4IiByeD0iMjgiIGZpbGw9IiNmZmY3ZWQiLz4KICAgIDxyZWN0IHg9IjY0NCIgeT0iMjY4IiB3aWR0aD0iNDg0IiBoZWlnaHQ9IjI4OCIgcng9IjI4IiBmaWxsPSIjZWZmNmZmIi8+CiAgPC9nPgogIDx0ZXh0IHg9IjEwOCIgeT0iMzIwIiBmaWxsPSIjOWEzNDEyIiBmb250LWZhbWlseT0iU2Vnb2UgVUksIEFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjMwIiBmb250LXdlaWdodD0iODAwIj5JbmdyZXNzPC90ZXh0PgogIDx0ZXh0IHg9IjEwOCIgeT0iMzUyIiBmaWxsPSIjN2MyZDEyIiBmb250LWZhbWlseT0iU2Vnb2UgVUksIEFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjIwIj5PbmUgcmVzb3VyY2UgcGx1cyBjb250cm9sbGVyLXNwZWNpZmljIGFubm90YXRpb25zPC90ZXh0PgogIDxyZWN0IHg9IjEyNiIgeT0iNDA0IiB3aWR0aD0iMTU2IiBoZWlnaHQ9Ijg0IiByeD0iMTgiIGZpbGw9IiNmZGJhNzQiLz4KICA8dGV4dCB4PSIyMDQiIHk9IjQzOCIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzdjMmQxMiIgZm9udC1mYW1pbHk9IlNlZ29lIFVJLCBBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyMCIgZm9udC13ZWlnaHQ9IjgwMCI+SW5ncmVzczwvdGV4dD4KICA8dGV4dCB4PSIyMDQiIHk9IjQ2NiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZmlsbD0iIzdjMmQxMiIgZm9udC1mYW1pbHk9IlNlZ29lIFVJLCBBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxOCI+aG9zdC9wYXRoIHJ1bGVzPC90ZXh0PgogIDxyZWN0IHg9IjMyNCIgeT0iMzkyIiB3aWR0aD0iMTc0IiBoZWlnaHQ9IjEwOCIgcng9IjE4IiBmaWxsPSIjZmVkN2FhIi8+CiAgPHRleHQgeD0iNDExIiB5PSI0MjYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiM3YzJkMTIiIGZvbnQtZmFtaWx5PSJTZWdvZSBVSSwgQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTkiIGZvbnQtd2VpZ2h0PSI4MDAiPmFubm90YXRpb25zPC90ZXh0PgogIDx0ZXh0IHg9IjQxMSIgeT0iNDU0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjN2MyZDEyIiBmb250LWZhbWlseT0iU2Vnb2UgVUksIEFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjE4Ij5UTFMsIGNhbmFyeSwgcmVkaXJlY3RzPC90ZXh0PgogIDx0ZXh0IHg9IjQxMSIgeT0iNDgwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjN2MyZDEyIiBmb250LWZhbWlseT0iU2Vnb2UgVUksIEFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjE4Ij5jb250cm9sbGVyIGJlaGF2aW9yPC90ZXh0PgogIDxwYXRoIGQ9Ik0yODQgNDQ2aDI4IiBzdHJva2U9IiNjMjQxMGMiIHN0cm9rZS13aWR0aD0iMTIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgoKICA8dGV4dCB4PSI2ODAiIHk9IjMyMCIgZmlsbD0iIzFlM2E4YSIgZm9udC1mYW1pbHk9IlNlZ29lIFVJLCBBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIzMCIgZm9udC13ZWlnaHQ9IjgwMCI+R2F0ZXdheSBBUEk8L3RleHQ+CiAgPHRleHQgeD0iNjgwIiB5PSIzNTIiIGZpbGw9IiMxZTQwYWYiIGZvbnQtZmFtaWx5PSJTZWdvZSBVSSwgQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjAiPkF0dGFjaG1lbnQgYW5kIG93bmVyc2hpcCBhcmUgZmlyc3QtY2xhc3M8L3RleHQ+CiAgPHJlY3QgeD0iNjc2IiB5PSI0MDIiIHdpZHRoPSIxMjIiIGhlaWdodD0iODYiIHJ4PSIxOCIgZmlsbD0iIzkzYzVmZCIvPgogIDx0ZXh0IHg9IjczNyIgeT0iNDM3IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMWUzYThhIiBmb250LWZhbWlseT0iU2Vnb2UgVUksIEFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjE4IiBmb250LXdlaWdodD0iODAwIj5HYXRld2F5Q2xhc3M8L3RleHQ+CiAgPHRleHQgeD0iNzM3IiB5PSI0NjMiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMxZTNhOGEiIGZvbnQtZmFtaWx5PSJTZWdvZSBVSSwgQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTciPmluZnJhIGNob2ljZTwvdGV4dD4KICA8cGF0aCBkPSJNODAwIDQ0NWg0NiIgc3Ryb2tlPSIjMWQ0ZWQ4IiBzdHJva2Utd2lkdGg9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KICA8cmVjdCB4PSI4NTIiIHk9IjQwMiIgd2lkdGg9IjExMCIgaGVpZ2h0PSI4NiIgcng9IjE4IiBmaWxsPSIjYmZkYmZlIi8+CiAgPHRleHQgeD0iOTA3IiB5PSI0MzciIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMxZTNhOGEiIGZvbnQtZmFtaWx5PSJTZWdvZSBVSSwgQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTgiIGZvbnQtd2VpZ2h0PSI4MDAiPkdhdGV3YXk8L3RleHQ+CiAgPHRleHQgeD0iOTA3IiB5PSI0NjMiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiMxZTNhOGEiIGZvbnQtZmFtaWx5PSJTZWdvZSBVSSwgQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTciPmxpc3RlbmVycyArIFRMUzwvdGV4dD4KICA8cGF0aCBkPSJNOTY0IDQ0NWg0NCIgc3Ryb2tlPSIjMWQ0ZWQ4IiBzdHJva2Utd2lkdGg9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz4KICA8cmVjdCB4PSIxMDEyIiB5PSI0MDIiIHdpZHRoPSI5MiIgaGVpZ2h0PSI4NiIgcng9IjE4IiBmaWxsPSIjZGJlYWZlIi8+CiAgPHRleHQgeD0iMTA1OCIgeT0iNDM3IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMWUzYThhIiBmb250LWZhbWlseT0iU2Vnb2UgVUksIEFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjE4IiBmb250LXdlaWdodD0iODAwIj5IVFRQUm91dGU8L3RleHQ+CiAgPHRleHQgeD0iMTA1OCIgeT0iNDYzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMWUzYThhIiBmb250LWZhbWlseT0iU2Vnb2UgVUksIEFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjE3Ij5tYXRjaGVzICsgZmlsdGVyczwvdGV4dD4KICA8dGV4dCB4PSI2ODAiIHk9IjUyOCIgZmlsbD0iIzFlNDBhZiIgZm9udC1mYW1pbHk9IlNlZ29lIFVJLCBBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxOCI+cGFyZW50UmVmcyArIGFsbG93ZWRSb3V0ZXMgKyBSZWZlcmVuY2VHcmFudCBmb3IgY3Jvc3MtbmFtZXNwYWNlIHNhZmV0eTwvdGV4dD4KPC9zdmc+) Gateway API separates infrastructure ownership from routing ownership, replacing annotation-heavy ingress behavior with explicit attachment and policy boundaries. ## Ingress Solved the First Problem, Not the Current One [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-2) The Kubernetes docs now say the quiet part out loud: Kubernetes recommends [Gateway API](https://gateway-api.sigs.k8s.io/) instead of [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/), and the Ingress API is frozen. In practice, that means Ingress still works and is not going away, but it is no longer where new traffic-management capability is being standardized. That matters because most real-world platform problems were never just "route `/foo` to Service A and `/bar` to Service B." Teams need: - Shared edge infrastructure across namespaces and teams - Clear ownership boundaries between platform and application teams - Rich routing without vendor-specific annotations - Safer cross-namespace references - Consistent status and conformance signals across implementations Ingress can do basic host and path routing well. The model starts to strain when you need explicit listeners, reusable traffic entry points, weighted backends, structured filters, or a clean separation between "who owns the load balancer" and "who owns the app routing rules." This is what a typical annotation-heavy Ingress tends to look like: ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: checkout namespace: apps annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "10" spec: ingressClassName: nginx tls: - hosts: - shop.example.com secretName: shop-example-com rules: - host: shop.example.com http: paths: - path: /checkout pathType: Prefix backend: service: name: checkout-v1 port: number: 8080 ``` The problem is not that this YAML is invalid. The problem is that most of the interesting behavior lives in controller-specific annotations instead of a portable API. ## Gateway API Splits the Model Along Real Ownership Boundaries [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-3) The upstream Gateway API project describes itself as the next generation of Kubernetes ingress, load balancing, and service mesh APIs, and its design is explicitly role-oriented. That role split is the first major difference from Ingress. At minimum, the ingress use case is modeled through three stable resources: - [`GatewayClass`](https://gateway-api.sigs.k8s.io/reference/api-types/gatewayclass/): cluster-scoped infrastructure class owned by the controller or platform provider - [`Gateway`](https://gateway-api.sigs.k8s.io/reference/api-types/gateway/): the actual traffic entry point, with listeners, ports, addresses, and TLS - [`HTTPRoute`](https://gateway-api.sigs.k8s.io/reference/api-types/httproute/): application routing rules that attach to a Gateway `GatewayClass` is close to `IngressClass` conceptually, but it is a stronger contract. It tells you which controller implements the class and can carry a `parametersRef` for controller-specific configuration. `Gateway` then becomes the explicit declaration of entry points that were implicit in Ingress. `HTTPRoute` is where application teams describe matching and forwarding behavior. Here is the same shape of traffic expressed with Gateway API instead of a single Ingress: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: GatewayClass metadata: name: internet spec: controllerName: example.net/gateway-controller --- apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: edge namespace: infra spec: gatewayClassName: internet listeners: - name: http protocol: HTTP port: 80 hostname: shop.example.com allowedRoutes: namespaces: from: Selector selector: matchLabels: shared-gateway-access: 'true' - name: https protocol: HTTPS port: 443 hostname: shop.example.com tls: mode: Terminate certificateRefs: - kind: Secret name: shop-example-com allowedRoutes: namespaces: from: Selector selector: matchLabels: shared-gateway-access: 'true' --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: checkout namespace: apps labels: shared-gateway-access: 'true' spec: parentRefs: - name: edge namespace: infra sectionName: https hostnames: - shop.example.com rules: - matches: - path: type: PathPrefix value: /checkout backendRefs: - name: checkout-v1 port: 8080 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: redirect-http-to-https namespace: apps labels: shared-gateway-access: 'true' spec: parentRefs: - name: edge namespace: infra sectionName: http hostnames: - shop.example.com rules: - filters: - type: RequestRedirect requestRedirect: scheme: https port: 443 ``` That extra verbosity is the point. You can now reason about who owns the edge, who owns TLS termination, and who owns the route rules without smuggling everything through one resource. ## The Attachment Model Is the Real Upgrade [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-4) The most important Gateway API idea is not just "better HTTP routing." It is the attachment model. With Ingress, the relationship between infrastructure and application routing is mostly implicit: the Ingress chooses a class, the controller merges rules, and annotations decide much of the behavior. With Gateway API, attachment is explicit and bidirectional: - A Route requests attachment through `parentRefs` - A Gateway listener decides which Route kinds and namespaces may attach through `allowedRoutes` - A Route can bind to a specific listener using `sectionName` - [Cross-namespace references](https://www.google.com/search?ved=1t:260882&q=Kubernetes+Gateway+API+cross-namespace+references&bbid=3735948330054827072&bpid=826535620348174322) to backends or Secrets require a [`ReferenceGrant`](https://gateway-api.sigs.k8s.io/reference/api-types/referencegrant/) This matters in multi-team clusters because "can reference" and "is allowed to reference" are separate permissions. The following example shows a shared Gateway in `infra`, an application route in `apps`, and a backend Service in `shared-services`. The Route can only use that cross-namespace backend because the owner of `shared-services` explicitly grants it: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: shared-edge namespace: infra spec: gatewayClassName: internet listeners: - name: web protocol: HTTP port: 80 allowedRoutes: namespaces: from: Selector selector: matchLabels: gateway-access: shared-edge --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: store namespace: apps labels: gateway-access: shared-edge spec: parentRefs: - name: shared-edge namespace: infra sectionName: web hostnames: - store.example.com rules: - matches: - path: type: PathPrefix value: /session backendRefs: - name: shared-session-api namespace: shared-services port: 8080 - matches: - path: type: PathPrefix value: / backendRefs: - name: store-frontend port: 8080 --- apiVersion: gateway.networking.k8s.io/v1beta1 kind: ReferenceGrant metadata: name: allow-apps-to-shared-session-api namespace: shared-services spec: from: - group: gateway.networking.k8s.io kind: HTTPRoute namespace: apps to: - group: '' kind: Service name: shared-session-api ``` This is a cleaner security story than broad controller permissions plus annotation conventions. The route owner, gateway owner, and backend owner each participate in the final attachment. ## HTTPRoute Is Structured Enough to Replace a Lot of Annotations [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-5) The upstream migration guide calls out the reason many teams want Gateway API: it covers the basic Ingress feature set and also standardizes several capabilities that often used to be controller-specific annotations. `HTTPRoute` includes structured matches, filters, weighted backends, and timeouts. From the official docs: - `HTTPRoute` itself has been in the [Standard channel](https://www.google.com/search?ved=1t:260882&q=Kubernetes+API+Standard+channel+definition&bbid=3735948330054827072&bpid=826535620348174322) since `v0.5.0` - HTTPRoute timeouts have been in the Standard channel since `v1.2.0` - Core filters must be supported; extended filters depend on implementation That makes this kind of routing possible without hiding intent in string annotations: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: checkout-advanced namespace: apps spec: parentRefs: - name: edge namespace: infra sectionName: https hostnames: - shop.example.com rules: - matches: - path: type: PathPrefix value: /api/checkout headers: - type: Exact name: x-release-channel value: beta method: POST filters: - type: RequestHeaderModifier requestHeaderModifier: add: - name: x-routed-by value: gateway-api timeouts: request: 10s backendRequest: 2s backendRefs: - name: checkout-v1 port: 8080 weight: 90 - name: checkout-v2 port: 8080 weight: 10 ``` Several things are better here than the Ingress equivalent: - Path, method, and header matching are typed fields instead of controller conventions - Traffic splitting is a first-class API field on `backendRefs` - Timeout configuration is structured instead of annotation-specific - Status can report whether the Route was accepted by the target Gateway One important caveat: Gateway API is portable, but not every implementation supports every extended feature. Upstream publishes per-version [conformance reports](https://gateway-api.sigs.k8s.io/implementations/v1.4/) for exactly this reason. Before you rely on timeouts, special filters, or non-HTTP route types, check your controller's conformance level instead of assuming feature parity. ## Current Gateway API Maturity: What Is Stable and What Still Needs Verification [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-6) If you evaluate Gateway API as one giant feature bucket, you will either underuse it or overestimate it. The upstream versioning model is feature-based, not monolithic. As of the current official docs: - `GatewayClass`, `Gateway`, and `HTTPRoute` are GA and in the Standard channel - `GRPCRoute` is GA and in the Standard channel since `v1.1.0` - HTTPRoute timeouts are in the Standard channel since `v1.2.0` - `ReferenceGrant` is in the Standard channel and is the required safety mechanism for cross-namespace references - `TLSRoute` is GA in the Standard channel since `v1.5.0` - `TCPRoute` is still documented as Experimental - The general [policy attachment pattern](https://gateway-api.sigs.k8s.io/reference/policy-attachment/) is still marked Experimental That last point is where teams get sloppy. "Gateway API supports policy attachment" is true at the design-pattern level, but it does not mean every policy CRD you encounter is portable or mature. Treat policy resources such as backend-traffic or backend-TLS policies as controller-specific until your implementation documents them clearly. A practical rule: - Design around Standard-channel resources first - Use Experimental route types only when your controller and upgrade process can tolerate change - Treat policy CRDs like any other extension: verify controller support, status behavior, and upgrade semantics before adopting them in production ## Migration Guidance That Minimizes Surprises [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-7) The official Gateway API migration guide is useful, but the safest production migration is more operational than syntactic. ### 1. Inventory your annotations before you convert anything [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-1-inventory-your-annotations-before-you-convert-anything) Split your current Ingress configuration into three buckets: - Portable today: hostnames, path rules, TLS termination, redirects, header manipulation, weighted backends - Likely portable but controller-dependent: timeouts, special filters, gRPC-specific routing - Still implementation-specific: custom auth, vendor rate limits, health-check knobs, bespoke annotations If your existing behavior depends heavily on annotation-specific extensions, do not promise a one-file translation. ### 2. Install standard Gateway API CRDs and verify the controller you actually run [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-2-install-standard-gateway-api-crds-and-verify-the-controller-you-actually-run) The upstream getting-started guide currently points to the standard install bundle: ```bash kubectl apply --server-side -f \ https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.1/standard-install.yaml kubectl get gatewayclass ``` Then verify your implementation against the official conformance matrix and your vendor docs. ### 3. Model the Gateway first, then attach one hostname or path group at a time [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-3-model-the-gateway-first-then-attach-one-hostname-or-path-group-at-a-time) Ingress hides entry points. Gateway API makes them explicit. Start by creating the `Gateway` with the listeners, TLS config, and namespace attachment rules you want long term. Then move application rules into `HTTPRoute` resources incrementally instead of translating every Ingress into a single giant route object. ### 4. Use side-by-side migration, not a flag day [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-4-use-side-by-side-migration-not-a-flag-day) Gateway API is a good fit for parallel migration because you can stand up new listeners and Routes while the old Ingress continues serving traffic. If your controller supports weighted backends or you front everything with external DNS or load-balancer controls, you can shift hostname by hostname instead of cutting over the whole edge at once. ### 5. Leave extensions and policies for last [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-5-leave-extensions-and-policies-for-last) The upstream migration guide explicitly warns that some advanced features still depend on Gateway-specific extension points. That is where migrations get risky. First port the portable routing behavior. Only after that should you decide whether a given annotation maps to: - A standard `HTTPRoute` feature - An implementation-specific filter or extension reference - A policy CRD - A behavior you should drop because it is no longer worth carrying forward ### 6. Use conversion tools as scaffolding, not truth [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-6-use-conversion-tools-as-scaffolding-not-truth) The official guide mentions [`ingress2gateway`](https://gateway-api.sigs.k8s.io/guides/getting-started/migrating-from-ingress/). That is useful for initial translation, but generated output still needs a human review for ownership boundaries, listener layout, cross-namespace references, and controller support. ## Why This Model Scales Better for Platform Teams [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-8) Ingress was optimized for "get HTTP into the cluster." Gateway API is optimized for "let multiple teams share traffic infrastructure without pretending they all own the same thing." That is why the resource split is worth the extra YAML: - Platform teams can own `GatewayClass` and `Gateway` - App teams can own `HTTPRoute` - Shared gateways can be guarded with explicit attachment rules - Cross-namespace references require consent from the referenced namespace - Feature maturity is documented per resource and per capability, not buried in controller release notes If your cluster is simple and one team owns everything, Ingress can still be enough. If your environment has shared edge infrastructure, multiple namespaces, or a need to stop encoding routing features as annotations, Gateway API is the better control surface. ## Complete the namespace attachment and migration checks [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-9-2) `allowedRoutes.namespaces.selector` selects labels on the Namespace. Labels on an HTTPRoute alone do not satisfy it. This Namespace supplies the labels referenced by the listener examples; choose an authorized namespace policy rather than copying the label to every tenant. Both HTTP and HTTPS listeners need an explicit cross-namespace attachment policy when routes reside in `apps`. [Gateway cross-namespace routing](https://gateway-api.sigs.k8s.io/guides/user-guides/multiple-ns/). ```yaml apiVersion: v1 kind: Namespace metadata: name: apps labels: shared-gateway-access: 'true' gateway-access: shared-edge ``` **ReferenceGrant scope:** Permission for a route to attach to a Gateway is separate from permission to reference a backend in another namespace. The Service grant example is scoped to `shared-session-api`; substitute the actual backend Service name and inspect the grant in that Service's namespace. A grant without `to.name` permits the referenced kind more broadly. [ReferenceGrant documentation](https://gateway-api.sigs.k8s.io/reference/api-types/referencegrant/). The store route uses separate path rules for the frontend and session API. Multiple backend references in one rule distribute requests among alternative backends; they do not call the frontend and then the session API in sequence. The illustrative `/session` prefix must match the real API; this rule does not rewrite the path. **AWS implementation gate:** Check the installed AWS Load Balancer Controller version, Gateway API release/channel, accepted GatewayClass, supported route kinds and conformance features before migration. Inspect listener and route status, certificate resolution and backend health. A YAML parse or a supported CRD alone does not prove the controller implements a feature. [AWS controller Gateway guidance](https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/guide/gateway/gateway/). Keep the old Ingress front door operating while validating the new Gateway. HTTPRoute backend weights divide traffic within that route; they do not by themselves split incoming traffic between separate Ingress and Gateway front doors. Choose and test an external cutover method, such as DNS or the relevant load-balancer routing mechanism. Separate a rollback of that front-door change from reversal of application writes or schema changes. ## Frequently Asked Questions [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-9) **Q: Should every existing Ingress be migrated immediately?** A: No. Ingress is stable and supported; it is just frozen. Migrate when you need cleaner ownership, richer routing, better portability, or multi-namespace attachment controls that Ingress does not model well. **Q: Do I always need `GatewayClass`, `Gateway`, and `HTTPRoute`?** A: For the ingress use case, yes, that is the core model. `GatewayClass` selects the controller, `Gateway` defines the entry points and listener policy, and `HTTPRoute` carries the application routing rules. **Q: Is Gateway API only for HTTP traffic?** A: No. The project covers multiple protocols. Today, `HTTPRoute`, `GRPCRoute`, and `TLSRoute` are in the Standard channel, while `TCPRoute` is still documented as Experimental. That means your migration plan should be protocol-aware, not just HTTP-aware. **Q: What is the most common migration mistake?** A: Treating Gateway API as a one-to-one YAML rewrite of Ingress. The better approach is to redesign the ownership model first, especially listeners, namespace attachment, and which teams are allowed to reference which backends. **Q: When should I use policy attachment?** A: Only when you have confirmed that your controller supports the specific policy CRD you want and you understand its precedence and status behavior. The upstream policy attachment pattern is still experimental, so it should not be your default migration assumption. ## Resources [Section link](https://devopsdreams.blogspot.com/2026/03/kubernetes-gateway-api-vs-ingress_0191819753.html#dd-section-10) - [Kubernetes Ingress docs](https://kubernetes.io/docs/concepts/services-networking/ingress/) - [Gateway API introduction](https://gateway-api.sigs.k8s.io/) - [Gateway API getting started](https://gateway-api.sigs.k8s.io/guides/getting-started/) - [Migrating from Ingress](https://gateway-api.sigs.k8s.io/guides/getting-started/migrating-from-ingress/) - [GatewayClass reference](https://gateway-api.sigs.k8s.io/reference/api-types/gatewayclass/) - [Gateway reference](https://gateway-api.sigs.k8s.io/reference/api-types/gateway/) - [HTTPRoute reference](https://gateway-api.sigs.k8s.io/reference/api-types/httproute/) - [Cross-namespace routing guide](https://gateway-api.sigs.k8s.io/guides/multiple-ns/) - [ReferenceGrant reference](https://gateway-api.sigs.k8s.io/reference/api-types/referencegrant/) - [Gateway API versioning and release channels](https://gateway-api.sigs.k8s.io/docs/concepts/versioning/) - [Policy attachment reference](https://gateway-api.sigs.k8s.io/reference/policy-attachment/) - [Gateway API conformance reports](https://gateway-api.sigs.k8s.io/implementations/v1.4/)