Kubernetes
13 min readMay 2, 2026

Kubernetes Ingress vs Gateway API: When to Migrate and How

Gateway API v1.0.0 was released in October 2023 as a standalone SIG-Network project and is now the recommended way to manage external traffic. Ingress isn't going away, but it has real limitations that Gateway API was designed to fix. Here's what changed, what the migration looks like, and when it's worth doing.

AJ
Ajeet Yadav
Platform & Cloud Engineer
Kubernetes Ingress vs Gateway API: When to Migrate and How

Kubernetes Ingress has been the standard way to expose HTTP services since 1.1. It works, it's widely understood, and every Kubernetes cluster has an ingress controller. It also has fundamental limitations that have accumulated into a body of annotations-as-configuration workarounds that differ between every ingress controller implementation.

Gateway API is the replacement. Gateway API v1.0.0 was released in October 2023 as a standalone SIG-Network project — it has its own release cycle independent of Kubernetes. The CRDs are installed separately on any Kubernetes cluster; they are not bundled into Kubernetes itself. It has been production-ready since 2023 and is now the recommended path for new deployments. The question for existing clusters isn't whether to migrate — it's when and how.


What's Wrong with Ingress

Ingress was designed for a simple use case: route HTTP/HTTPS traffic to backend services based on hostname and path. That use case is common and the API handles it fine.

The problems emerge at the edges:

Annotations for everything beyond basics. Traffic splitting for canary deployments, header-based routing, request timeouts, retries, circuit breaking — none of these are in the Ingress spec. Controllers implement them as annotations, and the annotations differ between Nginx, Traefik, HAProxy, and cloud load balancers. A migration between ingress controllers means rewriting annotations, not just changing the controller.

No role separation. The Ingress API conflates infrastructure configuration (which load balancer class to use, TLS termination settings) with application configuration (routing rules). In a multi-team cluster, platform engineers manage the infrastructure and application teams manage their routes. Ingress has no way to express this separation.

Limited protocol support. Ingress is HTTP-only. TCP, UDP, gRPC, WebSocket, and other protocols are not in the spec. Again — annotations, or separate resources, or controller-specific workarounds.

No cross-namespace routing. An Ingress in namespace A cannot route to a Service in namespace B without controller-specific workarounds. Multi-namespace routing is a common requirement in multi-team clusters.


Gateway API Concepts

Gateway API introduces three core resources, each with a distinct owner:

GatewayClass

Defines a type of gateway (which controller implementation to use). Managed by infrastructure operators. Set once per cluster per implementation.

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx
spec:
  controllerName: gateway.nginx.org/nginx-gateway-controller

Gateway

An instance of a load balancer — the actual listener. Defines which ports, protocols, and hostnames it accepts. Managed by platform/network teams.

yaml
1apiVersion: gateway.networking.k8s.io/v1
2kind: Gateway
3metadata:
4  name: production-gateway
5  namespace: infra
6spec:
7  gatewayClassName: nginx
8  listeners:
9    - name: http
10      protocol: HTTP
11      port: 80
12    - name: https
13      protocol: HTTPS
14      port: 443
15      tls:
16        mode: Terminate
17        certificateRefs:
18          - name: production-tls
19            namespace: infra
20      allowedRoutes:
21        namespaces:
22          from: Selector
23          selector:
24            matchLabels:
25              gateway-access: allowed

The allowedRoutes field is the role-separation mechanism. The Gateway owner controls which namespaces can attach routes. Application teams in permitted namespaces can then attach their own HTTPRoute objects without needing access to the Gateway itself.

HTTPRoute

Defines routing rules — which requests go to which backend services. Managed by application teams, lives in the application's namespace.

yaml
1apiVersion: gateway.networking.k8s.io/v1
2kind: HTTPRoute
3metadata:
4  name: api-route
5  namespace: production    # Application team's namespace
6spec:
7  parentRefs:
8    - name: production-gateway
9      namespace: infra     # Reference the Gateway in the infra namespace
10  hostnames:
11    - "api.example.com"
12  rules:
13    - matches:
14        - path:
15            type: PathPrefix
16            value: /v1
17      backendRefs:
18        - name: api-service
19          port: 8080

This cross-namespace reference (HTTPRoute in production, Gateway in infra) is a first-class Gateway API feature — no annotations, no workarounds.


Feature Comparison

FeatureIngressGateway API
HTTP routing (path, host)
HTTPS/TLS termination
TCP/UDP routing❌ (annotations)✅ (TCPRoute, UDPRoute)
gRPC routing✅ (GRPCRoute, GA in Gateway API v1.1.0)
Traffic splitting (canary)❌ (annotations)✅ (weight-based backendRefs)
Header-based routing❌ (annotations)
Request/response modification❌ (annotations)✅ (filters)
Cross-namespace routing
Role separation✅ (GatewayClass/Gateway/Route)
Timeouts and retries❌ (annotations)✅ (timeouts in HTTPRoute)
Portable across controllers✅ (spec is standardised)

Traffic Splitting (Canary Without Annotations)

One of the most immediate benefits of Gateway API: canary deployments in the spec, not in annotations.

yaml
1apiVersion: gateway.networking.k8s.io/v1
2kind: HTTPRoute
3metadata:
4  name: api-canary
5  namespace: production
6spec:
7  parentRefs:
8    - name: production-gateway
9      namespace: infra
10  hostnames:
11    - "api.example.com"
12  rules:
13    - matches:
14        - path:
15            type: PathPrefix
16            value: /
17      backendRefs:
18        - name: api-stable
19          port: 8080
20          weight: 90
21        - name: api-canary
22          port: 8080
23          weight: 10

10% of traffic goes to api-canary, 90% to api-stable. To promote the canary, update weight: 100 on api-canary and weight: 0 on api-stable. To roll back, reverse it. No annotation syntax to remember, no controller-specific behaviour to learn.


Header-Based Routing

Route traffic to different backends based on request headers — useful for internal testing, feature flags, and A/B testing:

yaml
1rules:
2  - matches:
3      - headers:
4          - name: X-Feature-Flag
5            value: new-checkout
6    backendRefs:
7      - name: checkout-v2
8        port: 8080
9  - matches:
10      - path:
11            type: PathPrefix
12            value: /checkout
13    backendRefs:
14      - name: checkout-v1
15        port: 8080

Requests with X-Feature-Flag: new-checkout go to checkout-v2. All other /checkout traffic goes to checkout-v1. This is controller-agnostic — the same HTTPRoute works on Nginx, Envoy, or any conformant implementation.


Request Modification (Filters)

HTTPRoute supports built-in filters for request and response modification without annotations:

yaml
1rules:
2  - matches:
3      - path:
4          type: PathPrefix
5          value: /api/v1
6    filters:
7      - type: RequestHeaderModifier
8        requestHeaderModifier:
9          add:
10            - name: X-Request-Source
11              value: gateway
12          remove:
13            - X-Internal-Token
14      - type: URLRewrite
15        urlRewrite:
16          path:
17            type: ReplacePrefixMatch
18            replacePrefixMatch: /v1
19    backendRefs:
20      - name: api-service
21        port: 8080

This strips /api from the path (rewrites /api/v1/users to /v1/users), adds a header, and removes a sensitive header — all in the standard spec.


Supported Controllers

Gateway API is a spec; implementations are separate. Major implementations:

ControllerNotes
Nginx Gateway FabricF5/Nginx's official Gateway API implementation — separate from the legacy ingress controller
Envoy GatewayCNCF project, Envoy-based, strong Gateway API conformance
IstioFull Gateway API support in Istio 1.16+; replaces Istio's own Gateway CRDs
Traefik (v3+)Gateway API support as experimental → stable in v3
CiliumGateway API support built into Cilium 1.13+
AWS Load Balancer ControllerSupports Gateway API for ALB provisioning
GKENative Gateway API via GKE Gateway controller (Envoy-based)
AKSApplication Gateway for Containers supports Gateway API

Check conformance scores at gateway-api.sigs.k8s.io/implementations — not all controllers implement all features.


Migration from Ingress

Step 1: Inventory Your Ingress Objects

bash
kubectl get ingress -A -o yaml > ingress-export.yaml

For each Ingress, note:

  • Hostname and path rules
  • TLS configuration
  • Annotations (these need to be translated to Gateway API features or filters)
  • Which ingress class (kubernetes.io/ingress.class)

Step 2: Install a Gateway API Controller

If your existing ingress controller supports Gateway API (Nginx Gateway Fabric, Traefik v3, Cilium, Istio), you can use the same controller. Otherwise, install one:

bash
# Nginx Gateway Fabric
helm install nginx-gateway oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
  --namespace nginx-gateway \
  --create-namespace

Install the Gateway API CRDs — they are NOT bundled with any Kubernetes release and must be installed separately:

bash
# Gateway API CRDs are NOT included in Kubernetes itself.
# Install them explicitly, or rely on your cloud provider's pre-installed version (GKE, AKS do this).
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml

Step 3: Create GatewayClass and Gateway

yaml
1apiVersion: gateway.networking.k8s.io/v1
2kind: GatewayClass
3metadata:
4  name: nginx
5spec:
6  controllerName: gateway.nginx.org/nginx-gateway-controller
7---
8apiVersion: gateway.networking.k8s.io/v1
9kind: Gateway
10metadata:
11  name: production-gateway
12  namespace: infra
13spec:
14  gatewayClassName: nginx
15  listeners:
16    - name: https
17      protocol: HTTPS
18      port: 443
19      tls:
20        mode: Terminate
21        certificateRefs:
22          - name: production-tls
23      allowedRoutes:
24        namespaces:
25          from: All    # Loosen during migration, tighten after

Step 4: Translate Ingress to HTTPRoute

A simple Ingress:

yaml
1# Before: Ingress
2apiVersion: networking.k8s.io/v1
3kind: Ingress
4metadata:
5  name: api-ingress
6  namespace: production
7  annotations:
8    nginx.ingress.kubernetes.io/rewrite-target: /
9spec:
10  ingressClassName: nginx
11  rules:
12    - host: api.example.com
13      http:
14        paths:
15          - path: /api
16            pathType: Prefix
17            backend:
18              service:
19                name: api-service
20                port:
21                  number: 8080
yaml
1# After: HTTPRoute
2apiVersion: gateway.networking.k8s.io/v1
3kind: HTTPRoute
4metadata:
5  name: api-route
6  namespace: production
7spec:
8  parentRefs:
9    - name: production-gateway
10      namespace: infra
11  hostnames:
12    - "api.example.com"
13  rules:
14    - matches:
15        - path:
16            type: PathPrefix
17            value: /api
18      filters:
19        - type: URLRewrite
20          urlRewrite:
21            path:
22              type: ReplacePrefixMatch
23              replacePrefixMatch: /
24      backendRefs:
25        - name: api-service
26          port: 8080

Step 5: Run Both in Parallel

Keep the Ingress running while testing the HTTPRoute. Point a test subdomain to the new Gateway. Verify traffic flows correctly. Once validated, update DNS to point the production hostname to the Gateway's load balancer IP, and delete the Ingress.


When Not to Migrate Yet

Your controller doesn't have stable Gateway API support. Check conformance for your specific controller version. Partial conformance means some features behave differently than the spec describes.

You have complex annotations that don't map cleanly. Some controller-specific annotations have no direct Gateway API equivalent. If your Ingress relies heavily on Nginx-specific rate limiting or auth annotations, audit the equivalent mechanisms first.

Your team is mid-sprint. This is a non-trivial migration on complex clusters. Plan a maintenance window and rollback path.


Frequently Asked Questions

Is Ingress deprecated?

Not officially removed or deprecated in any current Kubernetes version. The Kubernetes SIG-Network has stated that Ingress will be maintained for the foreseeable future. But Gateway API is the direction of development — new features will go into Gateway API, not Ingress.

Do I need to run two ingress controllers?

Not necessarily. If your ingress controller supports Gateway API (Nginx Gateway Fabric, Traefik v3, Cilium), you can run Gateway API and Ingress resources simultaneously using the same controller, migrating routes incrementally.

Does Gateway API work with cert-manager?

Yes. cert-manager 1.14+ supports Gateway resources as certificate request targets via the gateway.networking.k8s.io/v1.Gateway reference. The annotation-based approach for Ingress still works too, so you can migrate TLS separately from routing.

What about service meshes?

Istio, Linkerd, and Cilium all support Gateway API for north-south traffic (external to cluster). For east-west traffic (pod-to-pod within the cluster), service meshes use their own APIs (or the experimental GAMMA initiative in Gateway API). For now, Gateway API is primarily relevant for ingress — not as a replacement for service mesh east-west policies.


For network-level security on top of routing, see Kubernetes Network Policies: A Practical Guide. For production ingress-nginx configuration including TLS, ModSecurity WAF, and rate limiting, see Kubernetes Ingress-NGINX in Production. For AWS ALB integration via the Load Balancer Controller, see AWS Load Balancer Controller on EKS. For an in-depth guide to Gateway API resources — HTTPRoute, GRPCRoute, ReferenceGrant, traffic splitting, and AWS ALB integration — see Kubernetes Gateway API: The Modern Replacement for Ingress.

Migrating from Ingress to Gateway API on a production cluster? Talk to us at Coding Protocols — we help platform teams manage traffic infrastructure migrations with zero downtime.

Related Topics

Kubernetes
Ingress
Gateway API
Networking
Platform Engineering
Traffic Management
Envoy

Read Next