Goodbye ingress-nginx, hello Gateway API
The most popular way into a Kubernetes cluster is retired. What that means, what Gateway API is, and how I'd move over without a weekend of downtime.
The most popular way into a Kubernetes cluster is retired. What that means, what Gateway API is, and how I'd move over without a weekend of downtime.

For years, the first thing I installed on almost every new Kubernetes cluster was ingress-nginx. Before the apps, before the monitoring, before anything interesting. It was the front door. Traffic came in, ingress-nginx sent it to the right place, and I rarely had to think about it.
That front door is now officially unmaintained. In November 2025, the Kubernetes project announced that ingress-nginx would be retired, with best-effort maintenance only until March 2026. That date has passed. If you're still running it, and a lot of clusters are, here's what that means and how I'd get out.
ingress-nginx was a community project, kept alive for years by a very small group of volunteers in their spare time. That's not a criticism. It's the uncomfortable truth behind a lot of the software we all depend on.
Security made it worse. In March 2025, a set of serious vulnerabilities nicknamed IngressNightmare showed that a bug in ingress-nginx could, in the worst case, let an attacker take over a whole cluster. Fixing that kind of thing properly takes time and people the project simply didn't have. So Kubernetes SIG Network and the Security Response Committee made the honest call: retire it. A planned successor, a project called InGate, never got far enough along and is being retired too.
Two things are easy to mix up here, so let me be clear:
Ingress resource still works. It's just frozen: no new features are coming.No. Your cluster didn't break when the maintenance ended. Existing installs keep running, and the images and Helm charts are still available.
But think about what this component is. It's the one thing in your cluster that faces the internet directly. It parses every request from strangers. And from now on, when the next vulnerability is found, nobody will fix it. That's not a "someday" problem. It's a "this quarter" problem.
Running unpatched software at the edge of your cluster is like leaving the front door unlocked because it has never been robbed yet.
First, find out if you're affected at all. This command, from the official announcement, lists any ingress-nginx pods across the cluster:
kubectl get pods --all-namespaces \
--selector app.kubernetes.io/name=ingress-nginx
If that returns nothing, you can relax and maybe skip to the end. If it returns pods, keep reading.
Gateway API is the official successor to Ingress. It isn't brand new, either: the core became stable back in 2023, and almost every major networking project and cloud provider supports it today.
The biggest change is that one big object becomes a few smaller ones, each owned by the right person:
/api to this service." Owned by the app team, in their own namespace.With Ingress, all of that was squeezed into one resource, and everything the spec didn't cover was hidden in annotations. Anyone who has seen an Ingress with fifteen nginx.ingress.kubernetes.io/... lines knows what I mean. Those annotations only worked with one controller, so "portable Kubernetes" stopped at the front door.
| Ingress | Gateway API | |
|---|---|---|
| Structure | One resource does everything | Separate pieces for platform and app teams |
| Advanced features | Controller-specific annotations | Built into the spec: header matching, traffic splitting, redirects |
| Protocols | HTTP and HTTPS | HTTP, gRPC, TLS, and TCP/UDP with some implementations |
| Portability | Low once annotations creep in | Much better: the same YAML works across implementations |
| Future | Frozen | Where all the new work happens |
Here's what it looks like in practice. First the Gateway, set up once by the platform team:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: web
namespace: infra
spec:
gatewayClassName: eg # e.g. Envoy Gateway
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- name: example-com-tls
allowedRoutes:
namespaces:
from: All # tighten this with a label selector later
Then each app team attaches its own route, in its own namespace:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: shop
namespace: shop
spec:
parentRefs:
- name: web
namespace: infra
hostnames: ["shop.example.com"]
rules:
- matches:
- path: { type: PathPrefix, value: /api }
backendRefs:
- name: shop-api
port: 8080
The app team never touches the Gateway, and the platform team never has to approve a routing change for someone else's service. That separation is what I like most. It matches how teams actually work.
Gateway API is only a specification. You still need something to run it. The good news is there are plenty of solid options:
Don't spend weeks comparing benchmarks. For most clusters, the honest deciding question is: what does my team already understand, and what will we still enjoy maintaining in three years?
The trick is to never do a big switch-over. Run both side by side, move traffic slowly, and keep a way back.
bash
kubectl get ingress -A -o yaml \
| grep -o 'nginx.ingress.kubernetes.io/[a-z-]*' \
| sort | uniq -c | sort -rn
The annotations are where the real work is hiding.
Install the new implementation next to the old one. It gets its own load balancer and its own IP. Nothing changes for users yet.
Convert with ingress2gateway. The Kubernetes project's own tool reached version 1.0 in March 2026. It reads your existing Ingress resources and writes the Gateway API equivalents:
bash
ingress2gateway print --providers=ingress-nginx \
--all-namespaces -o yaml > gateway-resources.yaml
Treat the output as a first draft, not the final answer. Review it like you'd review a pull request.
Fix by hand what the tool can't. Custom snippets, authentication, rate limiting, unusual rewrites and regex paths usually need manual work. Many of these become implementation-specific policies instead of annotations.
Test before DNS changes. Point requests directly at the new IP and check everything works:
bash
curl --resolve shop.example.com:443:NEW_GATEWAY_IP \
https://shop.example.com/api/health
Move traffic gradually. Lower your DNS TTLs a day before, then move one hostname at a time, starting with the least important. Keep ingress-nginx running so rolling back is just a DNS change.
Clean up. Once everything has run quietly for a while, remove ingress-nginx and its Ingress resources. Don't forget the tools around it: cert-manager and ExternalDNS both support Gateway API, but they need to be configured for it.
A few things are easy to underestimate:
configuration-snippet years ago, there's no direct translation. You first need to work out what it was even for. Sometimes the answer is "nothing anymore."rewrite-target with regex capture groups doesn't map one to one. Test every rewritten path.If you're building a new cluster, don't install ingress-nginx, and don't write new Ingress resources either. Start with Gateway API from day one. The concepts take an afternoon to learn, and you'll never have to do this migration.
And if you're learning Kubernetes, this is a good lesson in itself. The most popular project in its category, used by almost everyone, was maintained by a handful of tired volunteers. Before you build on something, it's worth asking who is actually keeping it alive.
Honestly, yes, and not only for security. Gateway API is simply the better model. Cleaner YAML, fewer magic annotations, a clear split between platform and app teams, and features that used to need hacks are now built in.
The retirement just forces a move most of us should have made anyway. Better to do it calmly now than in a hurry the day the next big vulnerability is announced.
My take: the front door changed, but the job didn't. Plan it, run both side by side, move slowly, and keep a way back.
— Desly