Skip to content

Ingress vs Gateway API: Planning the Move Now That ingress-nginx Is Retired

September 3, 2026 · 12 min read · by Harshit Luthra

Ingress is feature-frozen and every capability beyond host-and-path routing lives in controller-specific annotations. Gateway API replaces those annotations with typed, portable resources and a role split between platform and application teams. The urgency changed in March 2026, when the community ingress-nginx controller stopped receiving maintenance, including security fixes.

Something changed, and it was not the API

For years the honest answer to “should we move to Gateway API?” was “eventually, there is no rush”. Ingress worked, every controller supported it, and the annotation soup was ugly but familiar.

That answer expired in March 2026, when best-effort maintenance on the community ingress-nginx controller ended. Kubernetes SIG Network and the Security Response Committee announced the retirement in November 2025, and the Steering Committee reinforced it in January 2026. The consequence is concrete: no further releases, no bug fixes, and no patches for security vulnerabilities discovered from that point on.

Three clarifications, because these get conflated constantly and the panic is often misdirected:

  • The Ingress API is not deprecated. It is feature-frozen — nothing new is being added — but it remains part of Kubernetes and supported.
  • NGINX the web server is not affected, and neither is F5’s separate nginxinc/kubernetes-ingress controller, which is a different project that remains maintained.
  • Only the community ingress-nginx controller was retired. That happens to be the most widely deployed ingress controller in the world, which is why this matters at all.

If you are running it today, you are running an internet-facing component that no longer receives CVE fixes. That is a decision someone should make on purpose rather than discover during an audit.

Why Ingress ran out of room

Ingress v1 describes almost nothing: hostnames, paths, and a backend service. Everything a real production edge needs — timeouts, retries, rate limiting, header manipulation, redirects, rewrites, canary weights, mTLS, CORS, body size limits, authentication — lives in annotations.

Annotations are strings. They are not validated by the API server, they are not portable between controllers, and they have no schema. A typo in an annotation key is silently ignored: the controller does not know about that key, so it does nothing, and your rate limit simply is not applied. Nobody finds out until it matters.

# Every line below this is controller-specific, unvalidated, and untyped.
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Env: prod";

Change controllers and you rewrite all of it. That is exactly the tax a lot of teams are paying right now, and it is the reason “just move to a different Ingress controller” is less of a shortcut than it looks — you keep the API, but you throw away the annotations anyway.

What Gateway API actually is

Gateway API is a set of CRDs maintained by SIG Network, with HTTPRoute and friends reaching GA. Its central idea is a split by responsibility rather than one object that does everything:

  • GatewayClass — the kind of load balancer implementation available. Owned by the infrastructure provider.
  • Gateway — an actual listener: ports, protocols, TLS certificates, hostnames. Owned by the platform or cluster team.
  • HTTPRoute / GRPCRoute / TCPRoute / TLSRoute — routing rules attached to a Gateway. Owned by application teams, in their own namespaces.

That separation is the part that changes how a platform team operates. Today, giving an application team the ability to expose a service usually means giving them permission to create Ingress objects with arbitrary annotations, some of which can reconfigure shared edge behaviour. With Gateway API, the platform team owns the Gateway and its TLS, and application teams attach routes to it — with cross-namespace attachment requiring an explicit ReferenceGrant in the target namespace, so nobody can route to a service in another team’s namespace without that team agreeing.

# Platform team owns this. One listener, one certificate, one place.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: prod-edge
  namespace: gateway-system
spec:
  gatewayClassName: envoy
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      hostname: "*.example.com"
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-example-com
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              gateway-access: "true"
# Application team owns this, in their own namespace. No annotations.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api
  namespace: payments
spec:
  parentRefs:
    - name: prod-edge
      namespace: gateway-system
  hostnames: ["api.example.com"]
  rules:
    - matches:
        - path: { type: PathPrefix, value: /v2 }
          headers:
            - name: x-canary
              value: "true"
      backendRefs:
        - name: api-next
          port: 8080
    - matches:
        - path: { type: PathPrefix, value: /v2 }
      filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            set:
              - name: x-forwarded-env
                value: prod
      backendRefs:
        - name: api-stable
          port: 8080
          weight: 90
        - name: api-next
          port: 8080
          weight: 10

Everything in that second file is typed and validated. The weighted split is part of the specification rather than an annotation pair. Header matching, header modification, redirects, URL rewriting and request mirroring are core or extended features rather than per-controller inventions. A kubectl apply with a misspelled field is rejected, not silently ignored.

Ingress vs Gateway API, honestly

IngressGateway API
StatusSupported, feature-frozenWhere new capability is going
Config modelSpec plus controller-specific annotationsTyped CRDs, validated by the API server
Traffic splittingAnnotation, if your controller has oneNative backendRefs weights
Header / method matchingAnnotation or snippetIn the specification
Rewrites, redirects, mirroringAnnotation or snippetCore and extended filters
Multi-team ownershipOne object, one set of RBACGateway and Route split, ReferenceGrant for cross-namespace
Portability between controllersPoor — annotations do not transferGood for core features, less so for implementation-specific policy
ProtocolsHTTP/HTTPS in practiceHTTP, gRPC, TCP, TLS, UDP route types
MaturityVery mature, universally understoodGA for HTTP routing; some policy areas still evolving
Learning costEveryone already knows itThree or four new resource types and a mental model shift

The honest weakness of Gateway API is the last two rows. Core HTTP routing is stable and portable. The moment you need something outside the spec — a particular auth integration, a rate-limiting policy, WAF rules — you are back to implementation-specific resources, just better-typed ones. Portability improves; it does not become absolute.

Choosing an implementation

There are more implementations than is useful to list, and the right one depends on what you already run.

  • Already running Istio or Cilium? Both implement Gateway API. Use what you have rather than adding an edge proxy beside a mesh that already routes.
  • Want a plain, focused edge proxy? Envoy Gateway and Contour are both Envoy-based and both do the job without dragging in a mesh.
  • Want to stay in NGINX-land? NGINX Gateway Fabric is the Gateway API implementation from that lineage.
  • On a managed cloud? GKE and other managed offerings implement Gateway API against their own load balancers, which moves TLS and capacity out of your cluster.

Two selection criteria matter more than feature grids. First, who operates it — an edge proxy is on the critical path for every request, and the team that owns it needs to be able to debug it under pressure. Second, whether it fits the mesh question: if east-west traffic policy is on your roadmap, the GAMMA work extends Gateway API to service-mesh routing, and choosing an implementation that covers both saves you a second migration.

Migrating route by route

The good news is that Ingress and Gateway API coexist cleanly. They are different resource types handled by different controllers, so this is a gradual migration rather than a cutover — the same discipline as any zero-downtime Kubernetes migration.

  1. Inventory the annotations you actually depend on. Dump every Ingress in the cluster and collect the distinct annotation keys. This list is the real scope of the migration, and it is usually shorter than people fear — a handful of timeouts, body sizes, and rewrites, plus one or two snippets that somebody should have documented.
  2. Deal with configuration-snippet first. Raw snippets have no Gateway API equivalent by definition. Each one needs a decision: replace with a typed filter, move into the application, or accept an implementation-specific policy resource.
  3. Stand up a Gateway beside the existing ingress, on its own load balancer and its own DNS name. Nothing points at it yet.
  4. Move one low-risk hostname. Create the HTTPRoute, verify it against the new Gateway’s address directly, then shift DNS or upstream weight to it gradually. Keep the Ingress object in place — it is your rollback.
  5. Watch the status conditions. Gateway API reports attachment and acceptance in resource status, which is far better feedback than Ingress ever gave you. kubectl describe httproute tells you whether the route is actually bound to the Gateway and why not if it is not.
  6. Move the rest in batches, riskiest last, then retire the Ingress objects and the old controller only after everything has run on the new path through a peak period.
  7. Give the platform team the Gateway and application teams their routes, with ReferenceGrant where namespaces cross. Doing this at migration time is much easier than retrofitting it later.

The step people skip is 1. Without the annotation inventory, the migration is open-ended and stalls; with it, it is a finite list of decisions.

What to do this quarter

If you are on the retired ingress-nginx, the decision is not “Ingress or Gateway API”, it is “what do we do about an unmaintained internet-facing proxy”. Ranked by how I would advise most teams:

  1. Move to a Gateway API implementation. You do the work once and land where the ecosystem is going.
  2. Move to another maintained Ingress controller. Faster to reason about, but you rewrite the annotations anyway and you will likely do this again.
  3. Buy commercial support for a maintained fork. Legitimate if you have a hard freeze or a compliance timeline that makes migration impossible this year. It buys time, not a destination.

What is not an option is leaving it in place and not deciding. An unpatched edge proxy is exactly the class of exposure that a security and SRE hardening review exists to find, and it is the same category of problem as the public VPN listener replaced in the VPN to mesh engagement — a component everyone had stopped thinking about, sitting on the internet.

If you want the annotation inventory done and a migration plan written against your actual cluster, that is API gateways and networking work I do regularly. And if what you are seeing right now is errors rather than a planning question, the 502 vs 503 vs 504 debugging guide is the faster place to start.

Written by Harshit Luthra, an independent infrastructure and AI engineering consultant. Stuck on something similar? →

related

If this is live for you right now

Questions people ask about this

Is the Kubernetes Ingress API deprecated?+

No. The Ingress API itself is still supported and is not being removed, but it is feature-frozen — no new capability is being added to it. What was retired is the community-maintained ingress-nginx controller, which is a different thing from the Ingress API and also different from F5's separately maintained nginxinc/kubernetes-ingress controller.

What happened to ingress-nginx?+

Kubernetes SIG Network and the Security Response Committee announced its retirement in November 2025, and best-effort maintenance ended in March 2026. After that there are no further releases, no bug fixes, and no patches for newly discovered security vulnerabilities. If you are still running it, you are running an internet-facing component that will not receive CVE fixes, which is a risk decision someone in your organisation should be making explicitly.

Do I have to migrate to Gateway API?+

Not immediately, and not necessarily to Gateway API specifically. If you were on ingress-nginx, your realistic options are moving to another maintained Ingress controller, moving to a Gateway API implementation, or paying for commercial support on a fork. Gateway API is what the Kubernetes community recommends and where new capability is going, so for most teams doing the work once, it is the destination worth choosing.

What does Gateway API give me that Ingress annotations do not?+

Typed, portable configuration instead of controller-specific annotation strings. Header and method matching, weighted traffic splitting, request and response header modification, URL rewriting and request mirroring are all part of the specification rather than per-controller extensions. It also separates the Gateway (owned by the platform team) from the routes (owned by application teams), with explicit cross-namespace permission via ReferenceGrant.

Can I run Ingress and Gateway API at the same time?+

Yes, and that is the sane way to migrate. They are separate resource types handled by separate controllers, so you can stand up a Gateway alongside your existing ingress, move one hostname or one path prefix at a time, and keep the old path as an instant rollback until every route has moved and been observed under real traffic.

Want a second pair of eyes on this?

Book a free 30-minute call. We diagnose it together, and you walk away with a plan you can act on. You’ll get a straight read either way.