Ingress NGINX is retired: the Gateway API migration, 34 annotations mapped (2026)
Summary. Kubernetes SIG Network and the Security Response Committee retired Ingress NGINX: best-effort maintenance continued until March 2026, and after that there are "no further releases, no bugfixes, and no updates to resolve any security vulnerabilities that may be discovered," per the project's retirement announcement of November 11, 2025. Nothing breaks today: existing deployments keep working and installation artifacts remain available. The recommended path is Gateway API. The official migration tool, ingress2gateway, reached v1.0.0 on March 20, 2026 and v1.1.0 on April 29, 2026; it translates 34 ingress-nginx annotations, supports 9 providers and 5 emitters, and explicitly refuses to convert 7 annotations that Gateway API has no equivalent for. That refusal list is the part worth reading first.
Four months in, most teams have not moved. The migration is mechanical for maybe 80% of a typical config and genuinely unsolved for the rest, and knowing which is which before you start is the whole job.
What actually happened, and what did not
The retirement announcement is precise about scope, and the precision matters:
"Existing deployments of Ingress NGINX will continue to function and installation artifacts will remain available."
So this is not a deprecation with a shutdown date. Your cluster does not break. What stopped is the thing that matters over a two-year horizon: someone fixing the next CVE. Running an ingress controller that receives no security updates is a decision about risk tolerance, not uptime, and it is one that will get harder to defend to an auditor every month.
The committees' recommendation, verbatim: "We recommend migrating to one of the many alternatives. Consider migrating to Gateway API, the modern replacement for Ingress. If you must continue using Ingress, many alternative Ingress controllers are listed in the Kubernetes documentation."
Two paths, then. Swap to another Ingress controller and keep the Ingress API, or move to Gateway API. The rest of this guide covers the second, because the first only buys time.
The trap: there are two NGINX providers
Start here, because getting this wrong wastes an afternoon.
ingress2gateway ships two separate providers with confusingly similar names, and they are for different controllers:
| Provider flag | Controller | Annotation prefix |
|---|---|---|
ingress-nginx |
Community ingress-nginx (the retired one) | nginx.ingress.kubernetes.io/ |
nginx |
NGINX Ingress Controller (from NGINX/F5) | nginx.org/ |
traefik |
Traefik | Traefik-specific |
kong |
Kong | Kong-specific |
istio |
Istio | Istio-specific |
gce |
GCE | GCE-specific |
The nginx provider README says it outright: "This provider is specifically for NGINX Ingress Controller, not the community ingress-nginx controller. If you're using the community ingress-nginx controller, please use the ingress-nginx provider instead."
If you are reading this because of the retirement, you want --providers=ingress-nginx. The full provider list is apisix, cilium, ingress-nginx, istio, gce, kong, nginx, openapi and traefik. Emitters are a separate axis: standard (the default, plain Gateway API), agentgateway, envoy-gateway, gce and kgateway.
Install the tool
Three options, from the README:
# Homebrew, macOS and Linux
brew install ingress2gateway
# Go install
go install github.com/kubernetes-sigs/ingress2gateway@v1.0.0
# From source (needs Go 1.25.5 or later)
git clone https://github.com/kubernetes-sigs/ingress2gateway.git && cd ingress2gateway
make build
go install .
Note the README pins @v1.0.0 in its go install line while the latest release is v1.1.0, tagged April 29, 2026. If you want the v1.1.0 additions, pin v1.1.0 explicitly rather than copying the README command.
Run the conversion
The core command:
ingress2gateway print --providers=ingress-nginx
That does four things, per the README: reads your kubeconfig to get cluster credentials and the active namespace, searches for ingress-nginx resources in that namespace, converts them to Gateway API resources, and "warn[s] you of any untranslated fields or unsupported features."
That fourth step is the actual product. The YAML is the easy part.
Dry-run against a file instead of a live cluster:
ingress2gateway print --providers=ingress-nginx --input-file=my-ingress.yaml
The flags worth knowing:
| Flag | Short | Default | What it does |
|---|---|---|---|
--providers |
none, required | Comma-separated list of providers | |
--input-file |
Read from manifests instead of the cluster; yaml and json; repeatable | ||
--all-namespaces |
-A |
false | All namespaces; ignores --namespace
|
--namespace |
-n |
Namespace scope for the invocation | |
--output |
-o |
yaml | One of yaml, json, kyaml |
--allow-experimental-gw-api |
false | Include Experimental fields such as URLRewrite | |
--emitter |
standard | Which emitter generates the output |
One provider-specific flag catches people: --ingress-nginx-ingress-class defaults to nginx, not ingress-nginx. If your IngressClass is named ingress-nginx, pass --ingress-nginx-ingress-class=ingress-nginx or the tool selects nothing and you will think your cluster is empty.
What the output looks like
Gateway API resources live in the gateway.networking.k8s.io API group as CRDs. GatewayClass, Gateway and HTTPRoute have all been in the Standard Channel since v0.5.0 and are GA. A minimal Gateway, verbatim from the Gateway API getting-started guide:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-web
spec:
gatewayClassName: example
listeners:
- protocol: HTTP
port: 80
name: prod-web-gw
allowedRoutes:
namespaces:
from: Same
And the route that attaches to it:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: foo
spec:
parentRefs:
- name: prod-web
rules:
- backendRefs:
- name: foo-svc
port: 8080
The gatewayClassName: example there is a placeholder. GatewayClass is cluster-scoped, there must be at least one defined before any Gateway works, and each GatewayClass is handled by a single controller. Choosing that controller is a decision ingress2gateway does not make for you.
Cross-namespace routing is where Gateway API earns the migration. A route in one namespace attaching to a Gateway in another, verbatim from the API overview:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-route
namespace: gateway-api-example-ns2
spec:
parentRefs:
- kind: Gateway
name: foo-gateway
namespace: gateway-api-example-ns1
rules:
- backendRefs:
- name: foo-svc
port: 8080
The Gateway must opt in, by selector:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-gateway
namespace: gateway-api-example-ns1
spec:
gatewayClassName: foo-lb
listeners:
- name: prod-web
port: 80
protocol: HTTP
allowedRoutes:
kinds:
- kind: HTTPRoute
namespaces:
from: Selector
selector:
matchLabels:
expose-apps: "true"
This is the role split that Ingress never had: a platform team owns the Gateway and decides which namespaces may attach, while application teams own their HTTPRoutes. If your reason for migrating is a security review, this is the paragraph to put in front of it, not the annotation table.
How Ingress fields map
The README's field mapping, condensed:
| Ingress field | Becomes |
|---|---|
ingressClassName |
gatewayClassName on the generated Gateway. The kubernetes.io/ingress.class annotation behaves the same |
defaultBackend |
A Listener with no hostname, plus a catchall HTTPRoute referencing it |
tls[].hosts |
An HTTPS Listener per host: port 443, protocol HTTPS, tls.mode Terminate |
tls[].secretName |
listeners[].tls.certificateRefs on those HTTPS Listeners |
rules[].host |
A separate Listener per distinct host value |
rules[].http.paths[].path |
rules[].matches[].path.value on the HTTPRoute |
rules[].http.paths[].pathType |
rules[].matches[].path.type. Ingress Exact maps to Exact; Ingress Prefix maps to PathPrefix
|
rules[].http.paths[].backend |
rules[].backendRefs[] on the HTTPRoute |
One oddity to read carefully rather than copy: the README's own entry for rules[].host states that listeners[].port will be set to 80 and listeners[].protocol set to HTTPS. Port 80 with protocol HTTPS is not a combination that makes sense, so treat that line as a documentation defect and check what the tool actually emits for your plain-HTTP hosts before you apply anything.
Conflicts resolve by age. If two Ingress rules collide, for example the same path match with different backends, "an error will be reported for the one that sorted later," and Ingress resources with the oldest creation timestamp sort first. Your oldest Ingress wins, which is rarely the one you would have picked.
The 34 annotations it handles
The ingress-nginx provider translates 34 annotations, all prefixed nginx.ingress.kubernetes.io/, in nine groups:
Canary (7): canary, canary-by-header, canary-by-header-value, canary-weight, canary-weight-total, canary-by-header-pattern, canary-by-cookie. Header-based canary becomes an HTTPHeaderMatch; canary-weight becomes backend weights; canary-weight-total "defaults to 100."
Rewrite (2): rewrite-target converts to a URLRewrite filter with ReplaceFullPath. app-root converts to an HTTPRequestRedirect filter with status 302.
Redirect (7): permanent-redirect (default 301), permanent-redirect-code (301, 302, 303, 307, 308), temporal-redirect (default 302, and it "takes priority over permanent redirect"), temporal-redirect-code (301, 302, 303, 307), ssl-redirect, proxy-redirect-from, proxy-redirect-to.
Headers (4): upstream-vhost sets the Host request header via HTTPRequestHeaderModifier; connection-proxy-header; x-forwarded-prefix; custom-headers.
Timeouts (3): proxy-connect-timeout, proxy-send-timeout, proxy-read-timeout, each converted to Gateway API timeout configuration in seconds.
Body size (2): proxy-body-size, converted from nginx size format such as 10m to a Kubernetes resource quantity, and client-body-buffer-size.
Backend protocol (1): backend-protocol. GRPC or GRPCS produce GRPCRoute resources; HTTPS or GRPCS trigger BackendTLSPolicy creation; unsupported values such as FCGI emit a warning.
Regex, CORS, IP, TLS (15): use-regex switches path matches to PathMatchRegularExpression. Seven CORS annotations, with cors-allow-origin defaulting to *, cors-allow-credentials to true, and cors-max-age to 1728000. whitelist-source-range and denylist-source-range. Six proxy-ssl-* annotations, where proxy-ssl-verify must be on for BackendTLSPolicy creation. And ssl-passthrough, which replaces the HTTPRoute with a TLSRoute in passthrough mode and adds a port 443 Passthrough listener per matching hostname.
The 7 it will not convert
This is the list that decides your timeline.
| Annotation | Tool's stated reason |
|---|---|
canary-by-header-pattern |
"header pattern matching is not supported in the conversion" |
canary-by-cookie |
"cookie-based canary routing is not supported in the conversion" |
proxy-redirect-from |
"Recognized but not converted. A warning is emitted" |
proxy-redirect-to |
"Recognized but not converted. A warning is emitted" |
custom-headers |
"Recognized but not converted. A warning is emitted" |
proxy-ssl-verify-depth |
"TLS verification depth is not supported by Gateway API" |
proxy-ssl-protocols |
"TLS protocol configuration is not supported by Gateway API" |
Read the last two again. Those are not tool gaps; they are Gateway API gaps. If your compliance posture depends on pinning TLS protocol versions at the ingress, or on certificate chain depth verification, Gateway API does not currently express that and no amount of tooling will fix it. You will be terminating those policies somewhere else, or staying on Ingress with a different controller.
And one more, separate from the seven: rewrite-target works, but "path rewrites with capture group references (e.g. $1) are not supported and will be flagged." Regex capture rewrites are extremely common in real ingress-nginx configs. Expect this to be your biggest manual bucket.
The project is candid about the boundary. The README states that "widely used provider-specific annotations and/or CRDs may still not be supported," and that "Ingress2gateway is not intended to copy annotations from Ingress to Gateway API." It is a translator, not a compatibility shim. Anything not on the list, per the README: "you'll need to manually find a Gateway API equivalent."
A migration sequence that works
- Inventory first. Run
ingress2gateway print --providers=ingress-nginx -A --output=yaml > converted.yamland read the warnings, not the YAML. The warnings are your project plan. - Grep your live Ingress objects for the seven refused annotations and for
rewrite-targetvalues containing$. That set is your manual work; everything else is mechanical. - Pick a GatewayClass controller before you convert anything. ingress2gateway emits
gatewayClassNamefrom youringressClassName, but the controller behind that class is your decision, and the emitters list (agentgateway, envoy-gateway, gce, kgateway) hints at where the ecosystem has settled. - Convert one low-traffic namespace with
--input-filefirst, diff the output, apply to a non-production cluster. - Run both in parallel. Gateway API resources coexist with Ingress objects; nothing forces a cutover. Move hostnames one at a time.
- Only then delete the Ingress objects and the ingress-nginx controller.
The blunt version: the tool converts your config in a second and your outage risk lives entirely in step 2. Budget accordingly.
Version compatibility is worth pinning down before step 4. The README's support table maps ingress2gateway v1.0 to Gateway API v1.5.0, and notes that "the output of Ingress2Gateway v1.0 is generally forward-compatible with Gateway API v1.4." TLSRoute reached the Standard Channel in v1.5.0, which matters if you use ssl-passthrough. GRPCRoute has been Standard since v1.1.0. TCPRoute and UDPRoute are still Experimental and Alpha.
India-specific considerations
The clusters most exposed here are the ones nobody has touched in two years, and in Indian engineering orgs those are disproportionately the cost-optimised, single-controller setups running on older managed Kubernetes versions. Two practical notes.
First, an ingress controller with no security updates is a live finding in any DPDP-driven security review. The Digital Personal Data Protection Act 2023 does not name ingress controllers, but "we run an unmaintained component that terminates TLS for all customer traffic" is not an answer that survives a data protection audit. Teams working through that posture should read our notes on platform engineering and application modernization patterns.
Second, sequence this against your other Kubernetes work rather than on top of it. If you are already planning around Kubernetes 1.35's pod certificates and constrained impersonation or in-place pod resize for rightsizing, the Gateway API move belongs in the same maintenance window, because it touches the same manifests and the same review board.
What this guide does not tell you
Three honest gaps.
The exact day in March 2026 that maintenance ended is not stated in the retirement announcement, which says only "until March 2026." Do not plan against a specific date you read somewhere; plan against "no security fixes since March."
The Kubernetes blog published a follow-up statement from the Steering and Security Response Committees on January 29, 2026, a piece on surprising ingress-nginx behaviors before you migrate on February 27, 2026, and the Ingress2Gateway 1.0 announcement on March 20, 2026. Those are worth your time and are listed in the references, but their contents are not represented here.
Annotation support moves. v1.1.0 added from-to-www-redirect, app-root and ssl-passthrough support for ingress-nginx, plus a Traefik provider. Check the release notes against your own annotation inventory rather than trusting a list dated July 2026.
FAQ
When did Ingress NGINX stop receiving security updates?
Best-effort maintenance continued until March 2026. After that the project states there are no further releases, no bugfixes, and no updates to resolve any security vulnerabilities that may be discovered. The retirement was announced on November 11, 2025 by Kubernetes SIG Network and the Security Response Committee.
Will my cluster break now that Ingress NGINX is retired?
No. The announcement states that existing deployments of Ingress NGINX will continue to function and installation artifacts remain available. Nothing is switched off. The exposure is security: a vulnerability discovered tomorrow gets no fix, which makes this a risk decision rather than an availability deadline.
What is the official tool for migrating to Gateway API?
ingress2gateway, a Gateway API SIG-Network subproject. It reached v1.0.0 on March 20, 2026 and v1.1.0 on April 29, 2026. It reads Ingress resources and provider CRDs from a cluster or file and prints equivalent Gateway API resources, warning about untranslated fields and unsupported features.
Which ingress2gateway provider do I use for the retired controller?
Use --providers=ingress-nginx. The separate nginx provider targets the NGINX Ingress Controller from NGINX and F5, which uses nginx.org/ annotations, while the retired community controller uses nginx.ingress.kubernetes.io/ annotations. Confusing the two produces empty or wrong output. Also set --ingress-nginx-ingress-class if your IngressClass is not named nginx, which is the flag's default.
Which ingress-nginx annotations cannot be converted?
Seven are recognized but not converted: canary-by-header-pattern, canary-by-cookie, proxy-redirect-from, proxy-redirect-to, custom-headers, proxy-ssl-verify-depth and proxy-ssl-protocols. Each emits a warning during conversion. The last two are Gateway API limitations rather than tool gaps, since Gateway API does not express TLS verification depth or TLS protocol configuration at all, so no future tooling release will close those two.
Does rewrite-target migrate cleanly?
Partly. It converts to a URLRewrite filter using ReplaceFullPath, but the provider README states that path rewrites with capture group references such as $1 are not supported and will be flagged. Regex capture rewrites are common in production ingress-nginx configs, so this is usually the largest manual bucket in a migration.
Can I run Ingress and Gateway API side by side during migration?
Yes. Gateway API resources are CRDs in the gateway.networking.k8s.io API group and coexist with Ingress objects, so nothing forces a single cutover. Convert one namespace, apply it to a non-production cluster, then move hostnames individually before removing the Ingress objects and the controller.
Which Gateway API version should I target?
ingress2gateway v1.0's support table maps to Gateway API v1.5.0, and its output is described as generally forward-compatible with v1.4. GatewayClass, Gateway and HTTPRoute have been Standard Channel since v0.5.0. TLSRoute reached Standard in v1.5.0, which matters for ssl-passthrough. TCPRoute and UDPRoute remain Experimental and Alpha.
How eCorpIT can help
eCorpIT is a Gurugram-based technology consultancy whose senior engineering teams run Kubernetes platforms in production, and this migration is one we scope the way it actually behaves: inventory the refused annotations first, then plan. We audit your ingress-nginx footprint against the 34 supported and 7 unsupported annotations, identify the regex rewrites that need hand-work, choose a GatewayClass controller against your traffic and compliance needs, and stage a hostname-by-hostname cutover with both stacks live. If you are running an unmaintained ingress controller and need this closed before your next security review, contact us.
References
- Ingress NGINX Retirement: What You Need to Know — Kubernetes Blog, November 11, 2025.
- kubernetes-sigs/ingress2gateway README — retrieved July 16, 2026.
- ingress2gateway: Ingress Nginx Provider README — retrieved July 16, 2026.
- ingress2gateway: NGINX Ingress Controller Provider README — retrieved July 16, 2026.
- ingress2gateway releases — v1.1.0 tagged April 29, 2026; v1.0.0 tagged March 20, 2026.
- Deploying a simple Gateway — Gateway API documentation.
- Gateway API: API Overview — Gateway API documentation.
- Ingress NGINX: Statement from the Kubernetes Steering and Security Response Committees — Kubernetes Blog, January 29, 2026.
- Before You Migrate: Five Surprising Ingress-NGINX Behaviors You Need to Know — Kubernetes Blog, February 27, 2026.
- Announcing Ingress2Gateway 1.0: Your Path to Gateway API — Kubernetes Blog, March 20, 2026.
- Gateway API — SIG Network.
- Gateway API concepts — Kubernetes documentation.
- kubernetes/ingress-nginx — the community controller.
- nginx/kubernetes-ingress — NGINX Ingress Controller.
Last updated: July 16, 2026.
Top comments (0)