Gateway API is the successor to the Kubernetes Ingress API. Ingress put everything in one object, extended with controller-specific annotations. Gateway API splits traffic configuration into separate resources for separate roles: the platform team runs the gateway, and application teams attach their routes to it.
For a long time one piece was missing for clusters shared by multiple teams. Application teams could not manage their own hostnames and TLS certificates without changing the central gateway. ListenerSet closes that gap, and that is when we started moving our customers.
We are migrating every cluster we manage from ingress-nginx to Gateway API with Envoy Gateway. This article covers what changes and why we waited. How to plan the migration covers the how.
Why move away from Ingress now?
Two things happened. The Ingress API is frozen: it remains part of Kubernetes, but it gets no new features. And ingress-nginx, the most widely used Ingress controller, has been retired.
The Kubernetes project announced the retirement at KubeCon in November 2025, with maintenance ending on March 26, 2026. That took the community by surprise: until then, the expected end of life was 2027. Retired means no more releases, so no more security fixes.
Staying on ingress-nginx means running an unmaintained component on the edge of every cluster, directly exposed to the internet. That risk is not theoretical. NGINX itself is still patched regularly, and many new NGINX vulnerabilities affect ingress-nginx too. Without new ingress-nginx releases, those fixes no longer reach your cluster. That is the strongest reason to move. The second is that Gateway API is a better model for clusters shared by multiple teams.
What is Gateway API?
Gateway API is the Kubernetes standard for routing traffic into a cluster, maintained by the Kubernetes project itself. The core went GA in 2023. It has three layers, each owned by a different role:
- GatewayClass: which implementation handles traffic, such as Envoy Gateway. Chosen by the platform provider.
- Gateway: the actual proxy with its IP address and ports. Run by the platform team.
- Routes: which requests go to which application. Owned by application teams.
Ingress never made that split. One object held hostnames, certificates, routing rules and controller settings, and anyone who could edit it could change all of them.
How is Gateway API different from Ingress?
| Ingress | Gateway API | |
|---|---|---|
| Protocols | HTTP and HTTPS | HTTP, HTTPS, gRPC, TCP, UDP |
| Extra features | Controller-specific annotations | Part of the API, or typed policies |
| Ownership | One object for everything | Separate resources per role |
| Portability | Tied to one controller | Largely portable between implementations |
| Feedback on mistakes | Fails silently | Status on every resource |
The annotation point matters most in practice. An Ingress with ten ingress-nginx annotations only works with ingress-nginx, and a typo in an annotation fails silently. In Gateway API, redirects, rewrites, header changes and traffic splitting are part of the standard. The API validates them, and every resource reports whether it was accepted.
The other big change is configuration snippets. ingress-nginx let you inject raw NGINX configuration per application. That was powerful, and it was also a source of security issues and outages that were hard to debug. Gateway API has no equivalent. In our migrations, most snippets turned out to be header changes, redirects or rewrites that Gateway API handles natively. Some were no longer needed at all.
What was missing: ListenerSet
In the original Gateway API model, hostnames and TLS certificates are configured on the gateway itself. That works when one team owns both the gateway and the applications. On a shared cluster it doesn’t:
- Every new hostname means a change to the shared gateway, owned by the platform team.
- Every certificate is referenced from that one central object.
- One mistake on the gateway can affect every application behind it.
For a managed platform, this was a blocker. With Ingress, an application team could launch a new hostname with its certificate entirely by itself. With plain Gateway API, every new hostname would become a change request to us. We were not willing to make our customers slower than they were on ingress-nginx.
ListenerSet solves this. Application teams define their own hostnames and certificates in their own namespace, and attach them to the shared gateway. The platform team keeps control of the gateway; application teams are self-sufficient again. cert-manager issues certificates for ListenerSets, just as it did for Ingress. The cert-manager project wrote a good explanation of why ListenerSet is the missing piece.
ListenerSet started out as an experimental feature. In early 2026, Envoy Gateway and cert-manager shipped support for it. That was the moment we started migrating customer workloads, not before.
What is still different?
Some gaps remain, and it is better to know them before you start:
- No built-in WAF. ingress-nginx came with ModSecurity. Gateway API has no web application firewall out of the box. OWASP Coraza, an open-source WAF compatible with ModSecurity rules, runs on Envoy as a Go filter, a Wasm plugin or one of the newer dynamic modules. For customers who rely on a WAF, we run Coraza with the OWASP Core Rule Set on Envoy Gateway and take care of updates and monitoring. Customers manage their own rules and exceptions per application.
- Not everything is standard yet. Rate limiting, authentication and IP allowlists are configured with resources specific to your Gateway API implementation. They are well designed, but not portable.
- Defaults change. Things ingress-nginx did implicitly, such as HTTPS redirects and security headers, now need to be configured explicitly. Our gateways enforce a TLS baseline following the NCSC TLS guidelines; security headers are set per application.
Why did we choose Envoy Gateway?
There are several good Gateway API implementations, including Envoy Gateway, Cilium, Istio, kgateway and NGINX Gateway Fabric. We chose Envoy Gateway for three reasons:
- It’s open source and actively maintained. It is part of the Envoy project in the CNCF, and focused on being a Gateway API implementation.
- It covers what our customers used annotations for: rate limiting, IP allowlists, authentication, CORS, timeouts and retries.
- It supported ListenerSet early. Envoy Gateway was among the first implementations to ship ListenerSet support, the feature we were waiting for.
How do we run it?
On every cluster we manage, ownership follows the Gateway API roles:
- Guida owns the gateways, including high availability, access logs, metrics and dashboards. Our platform tooling runs on its own gateway, so it never shares a proxy with customer traffic.
- Application teams own their hostnames, certificates and routes, in their own namespaces, deployed through their own GitOps flow.
That is the same split we had with ingress-nginx, where we ran the controller and teams wrote their own Ingress objects. The difference is that the boundary is now part of the API instead of a convention.
The bottom line
Gateway API is a better model than Ingress for clusters that more than one team uses. Until ListenerSet arrived, it was also harder to use for exactly those clusters. Now that it has, there is no reason to keep running a retired ingress controller on the edge of your cluster.
Ready to migrate? Read how to plan a migration from ingress-nginx to Gateway API, or see how Gateway API is part of Guida managed Kubernetes.