Ingress Nginx retires: it's time for Kubernetes Gateway API

The Ingress Nginx controller is retiring next month, in March 2026. What comes next? I think it should be the Kubernetes Gateway API - and in this post I will explain why.

The classic Ingress resource has served us well for years. Most Kubernetes users know it by heart as the third part of the trio of Deployment, Service and Ingress that is needed to expose an application. And Ingress Nginx is probably the most popular Ingress controller. It is battle tested, has a large community and a couple of additional features hidden in annotations.

The Gateway API offers these and many more features with an elegant architecture and a clear syntax directly in the manifests. This way, we can get direct first-class support for features like canary deployments and OAuth2 authentication.

The Gateway API Resource Model

The Gateway API introduces a clear separation of concerns through three main resource types:

Gateway API Resource Model Image source: Kubernetes Gateway API Documentation

  • GatewayClass: Defines the type of gateway implementation (e.g., Nginx, Envoy, Istio).
  • Gateway: The actual gateway instance that listens on specific ports and protocols.
  • Routes (HTTPRoute, TCPRoute, etc.): Define how traffic is routed to services.

This separation means developers don’t need to worry about load balancer configuration, TLS certificates at the gateway level, or infrastructure details. And more importantly, the Routes have a much more powerful syntax than the old Ingress.

Ingress versus HTTPRoute: A Developer’s View

Let’s first look at the basic textbook example of exposing a web application. With the classic Ingress resource, it looks like this:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  namespace: my-namespace
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app
            port:
              number: 8000

And here’s the equivalent with the Gateway API. One defines an HTTPRoute resource:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app
  namespace: my-namespace
spec:
  parentRefs:
  - name: production-gateway
    namespace: platform-team
  hostnames:
  - myapp.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: my-app
      port: 8000

So far, they look similar. We get the same basic functionality with almost the same number of lines. However, experienced users know that they often needed additional pieces: for authentication, complex load balancing, and other advanced features, we usually needed annotations and sidecar containers. The next examples will show how to do this with the Gateway API.

Canary deployments and advanced routing

With Ingress Nginx, complex routing scenarios like traffic splitting or header-based routing require vendor-specific annotations or multiple Ingress resources. With HTTPRoute, these features are built into the spec.

A useful feature in high-traffic production environments is the ability to gradually roll out new versions. With the Gateway API, traffic splitting is a first-class feature:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app-canary
  namespace: my-namespace
spec:
  parentRefs:
  - name: production-gateway
  hostnames:
  - myapp.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    # Define two backend services with different weights
    - name: my-app-v1
      port: 8000
      weight: 90
    - name: my-app-v2
      port: 8000
      weight: 10

This sends 90% of traffic to version 1 and 10% to version 2. Because this is defined declaratively in a single HTTPRoute resource, it’s easy to manage and version-control. A common workaround in the past involved running 9 replicas of the old version and 1 of the new version behind the same service. This replica-based approach is far less transparent and may need a lot more cluster resources just to handle the traffic.

The traffic flow looks like this:

graph LR Client[Client Requests] --> Gateway[Gateway] Gateway -->|90%| V1[my-app-v1] Gateway -->|10%| V2[my-app-v2] style V2 stroke:#f66,stroke-width:2px

OAuth2 Authentication with Envoy Gateway

Different Gateway implementations can extend the base Gateway API with additional features. Envoy Gateway, for example, provides some of its rich capabilities as a separate SecurityPolicy resource. By adding it to the HTTPRoute, you can enforce OAuth2 authentication, here with claim-based authorization:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: oauth2-with-claims
  namespace: my-namespace
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: my-app
  oidc:
    provider:
      issuer: https://auth.example.com
      authorizationEndpoint: https://auth.example.com/oauth2/authorize
      tokenEndpoint: https://auth.example.com/oauth2/token
    clientID: my-app-client-id
    clientSecret:
      name: oauth2-client-secret
    redirectURL: https://myapp.example.com/oauth2/callback
  authorization:
    rules:
    - action: ALLOW
      principal:
        jwt:
          provider: default
          claims:
          - name: role
            valueType: String
            values:
            - admin
            - developer

This configuration ensures that only users with the role claim set to either admin or developer can access the application.

In the past we solved this in much more complex ways:

  • by adding an Envoy sidecar with its complex configuration
  • by using a full service mesh (e.g. Istio)
  • by adding additional services and deployments (e.g. OAuth2 Proxy)

All of these solutions are solid and there are probably still valid use cases for them. But they are all much more complex and require more resources. And with good implementations, such as Envoy Gateway, you get it out of the box.

Summary

Moving from Ingress Nginx to the Gateway API might seem like extra work, but the benefits are substantial. With the comparison above, we have only scratched the surface of what the Gateway API can do:

  • Standardization: The Gateway API is a Kubernetes standard, not a vendor-specific solution
  • More expressive routing: Header matching, query parameter routing, traffic splitting, etc. are built-in
  • No more annotations: Vendor-specific features are now proper resources, not magic strings
  • Portable configurations: HTTPRoute works across different gateway implementations
  • Additional protocols: Support for additional protocols such as TCPRoute, UDPRoute or GRPCRoute
  • Modularity: The new configuration model enables easy extension via policies for external authentication and other advanced features.

All in all, we get a lot of features that previously required service mesh complexity. The Gateway API gives developers more power with less complexity, and it’s a standard that will be supported by all major vendors.

If you’re still using Ingress, now is the time to explore the Gateway API. Start with simple HTTPRoutes, experiment with traffic splitting, and discover how many of your previous workarounds can be replaced with standard syntax.

The next generation of Ingress is here, and Ingress Nginx can safely enjoy its retirement.

References

kubernetes   web services