- Authors
- Name
- Introduction
- Ingress vs Gateway API: Why Migrate?
- Understanding Core Resources
- Hands-On Migration Steps
- Gradual Transition Strategy
- Considerations and Troubleshooting
- Conclusion
- Quiz

Introduction
The Kubernetes networking stack is evolving. The Ingress API, which has long been the standard, is now being replaced by the Gateway API. Gateway API reached GA (General Availability) in 2023, and since 2025, most Ingress Controllers have begun supporting Gateway API.
In this post, we walk through the practical process of migrating existing Ingress resources to Gateway API, step by step.
Ingress vs Gateway API: Why Migrate?
Limitations of Ingress
The Ingress API works well enough for simple HTTP routing, but it has the following limitations:
- No role separation: Infrastructure administrators' and application developers' concerns are mixed in a single resource
- Limited protocol support: Only HTTP/HTTPS; TCP/UDP/gRPC require non-standard annotations
- Vendor lock-in: Different annotations per implementation (nginx, traefik, etc.)
- No header-based routing: Weighted traffic splitting not possible
Advantages of Gateway API
┌─────────────────────────────────────┐
│ GatewayClass │ ← Infrastructure provider (Platform team)
├─────────────────────────────────────┤
│ Gateway │ ← Cluster operator
├─────────────────────────────────────┤
│ HTTPRoute / TCPRoute / GRPCRoute │ ← Application developer
└─────────────────────────────────────┘
- Role-based design: Separation of concerns through the GatewayClass → Gateway → Route three-tier model
- Rich routing: Matching based on headers, query parameters, and methods
- Multi-protocol: Native support for HTTP, gRPC, TCP, UDP, and TLS
- Portability: Minimized vendor lock-in through a standard API
Understanding Core Resources
GatewayClass
A top-level resource defined by the infrastructure provider. It specifies which controller manages the Gateway.
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: nginx
spec:
controllerName: gateway.nginx.org/nginx-gateway-controller
Gateway
Defines the actual listeners (ports, protocols). Managed by cluster operators.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: main-gateway
namespace: infra
spec:
gatewayClassName: nginx
listeners:
- name: http
protocol: HTTP
port: 80
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: wildcard-cert
kind: Secret
allowedRoutes:
namespaces:
from: All
HTTPRoute
Application developers define routing rules here.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app-route
namespace: app-ns
spec:
parentRefs:
- name: main-gateway
namespace: infra
hostnames:
- 'app.example.com'
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: frontend-service
port: 3000
Hands-On Migration Steps
Step 1: Install Gateway API CRDs
# Install Gateway API v1.2 CRDs
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml
# Include experimental features (TCPRoute, TLSRoute, etc.)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml
# Verify installation
kubectl get crd | grep gateway
Step 2: Analyze Existing Ingress Resources
Before migrating, take stock of your existing Ingress resources:
# List all Ingress resources
kubectl get ingress -A -o wide
# Inspect a specific Ingress in detail (including annotations)
kubectl get ingress my-ingress -o yaml
Example of an existing Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: web-svc
port:
number: 3000
Step 3: Use the ingress2gateway Tool
Leverage the official conversion tool provided by the Kubernetes SIG:
# Install ingress2gateway
go install github.com/kubernetes-sigs/ingress2gateway@latest
# Convert Ingress resources in the current cluster to Gateway API
ingress2gateway print --all-namespaces
# Convert a specific namespace only
ingress2gateway print --namespace production
# Output to a file
ingress2gateway print --namespace production > gateway-resources.yaml
Step 4: Validate and Apply Converted Resources
# Validate with dry-run
kubectl apply -f gateway-resources.yaml --dry-run=server
# Apply
kubectl apply -f gateway-resources.yaml
# Check status
kubectl get gateway -A
kubectl get httproute -A
kubectl describe gateway main-gateway -n infra
Step 5: Traffic Splitting (Canary Deployment)
Weighted traffic splitting is a powerful feature unique to Gateway API:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
spec:
parentRefs:
- name: main-gateway
hostnames:
- 'app.example.com'
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-v1
port: 8080
weight: 90
- name: app-v2
port: 8080
weight: 10
Step 6: Header-Based Routing
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-route
spec:
parentRefs:
- name: main-gateway
rules:
- matches:
- headers:
- name: X-Version
value: beta
backendRefs:
- name: app-beta
port: 8080
- backendRefs:
- name: app-stable
port: 8080
Gradual Transition Strategy
Ingress and Gateway API can coexist in the same cluster:
- Phase 1: Install Gateway API CRDs + create GatewayClass/Gateway
- Phase 2: Use HTTPRoute for new services
- Phase 3: Convert existing Ingress resources to HTTPRoute one by one
- Phase 4: Remove all Ingress resources and clean up the Ingress Controller
# Monitor migration progress
echo "Ingress: $(kubectl get ingress -A --no-headers | wc -l)"
echo "HTTPRoute: $(kubectl get httproute -A --no-headers | wc -l)"
Considerations and Troubleshooting
Annotation Mapping
Ingress annotations are replaced by Policy resources or Filters in Gateway API:
| Ingress Annotation | Gateway API Equivalent |
|---|---|
rewrite-target | URLRewriteFilter |
ssl-redirect | HTTP-to-HTTPS redirect on Gateway listener |
rate-limit | BackendPolicy or implementation-specific Policy |
cors | HTTPRoute filter or Policy |
# URL Rewrite example
rules:
- matches:
- path:
type: PathPrefix
value: /old-api
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /new-api
backendRefs:
- name: api-svc
port: 8080
Common Mistakes
- Missing parentRefs namespace: If the Gateway and HTTPRoute are in different namespaces, the namespace must be specified
- Missing allowedRoutes configuration: Setting
from: Allis required for the Gateway to accept Routes from other namespaces - Missing ReferenceGrant: A ReferenceGrant is required for cross-namespace backend references
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-route-from-app
namespace: backend-ns
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-ns
to:
- group: ''
kind: Service
Conclusion
Gateway API is not just a replacement for Ingress — it represents a paradigm shift in Kubernetes networking. With role-based design, rich routing capabilities, and multi-protocol support, it enables safer and more flexible traffic management. Since it can coexist with existing Ingress resources, we recommend starting a gradual transition now.
Quiz
Q1: What are the names and responsible parties of each tier in Gateway API's three-tier resource model?
GatewayClass (Infrastructure provider / Platform team), Gateway (Cluster operator), HTTPRoute/TCPRoute etc. (Application developer)
Q2: What mechanism did Ingress use for vendor-specific configurations?
Annotations. Each implementation (nginx, traefik, etc.) used different non-standard annotations, which was a major cause of reduced portability.
Q3: What is the kubectl command to install Gateway API CRDs?
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml
Q4: What is the official tool that automatically converts existing Ingress to Gateway API resources?
ingress2gateway. Provided by the Kubernetes SIG, you can check the conversion results with the ingress2gateway print command.
Q5: Which field is used to implement weighted canary deployments in Gateway API?
The weight field in backendRefs. For example, setting weight: 90 for v1 and weight: 10 for v2 splits traffic in a 90:10 ratio.
Q6: What are two things to watch out for when HTTPRoute and Gateway are in different namespaces?
- The Gateway's namespace must be specified in parentRefs. 2) The Gateway's listeners must have allowedRoutes.namespaces.from set to "All".
Q7: What resource is needed when referencing a backend service across namespaces?
ReferenceGrant. Created in the target namespace, it specifies which resources from which namespaces are allowed to reference its Services.
Q8: How is the Ingress rewrite-target annotation replaced in Gateway API?
Using URLRewriteFilter in HTTPRoute filters. The path is rewritten using type: URLRewrite and the urlRewrite.path configuration.