Introduction
The Kubernetes Ingress resource has served the community well since its introduction in Kubernetes 1.2, but its limitations have become increasingly apparent as applications grow more complex. Ingress is intentionally simpleβit supports basic HTTP routing with host and path matching, TLS termination, and little else. Features like header-based routing, traffic splitting, request mirroring, and cross-namespace routing require vendor-specific annotations that vary between implementations and are difficult to standardize.
The Gateway API is the official successor to Ingress, designed from the ground up to address these limitations. It introduces a richer, more expressive routing model with role-based design that separates infrastructure concerns (GatewayClass) from cluster operations (Gateway) and application routing (HTTPRoute). This separation of concerns enables platform teams to define shared infrastructure while application teams independently manage their routing rules.
Gateway API reached GA (General Availability) with v1.0 in October 2023 and is now supported by all major ingress controller implementations including NGINX, Envoy, Istio, Traefik, HAProxy, and Kong. If you are starting a new project or planning to modernize your ingress layer, Gateway API is the path forward. This guide covers everything you need to know to migrate from Ingress to Gateway API.
Understanding Gateway API: Core Concepts
The Role-Based Model
Gateway API introduces three distinct resource types that map to different roles in an organization:
GatewayClass β Defined by infrastructure providers. A GatewayClass describes a type of gateway implementation (similar to a StorageClass for storage). Cluster administrators choose which GatewayClass to use based on the underlying implementation (NGINX, Envoy, etc.).
Gateway β Defined by cluster operators. A Gateway resource requests a load balancer or proxy from a GatewayClass. It defines listeners (ports, protocols, TLS configuration) and controls which namespaces can attach routes.
HTTPRoute / GRPCRoute / TCPRoute / TLSRoute / UDPRoute β Defined by application developers. Route resources define the actual routing rulesβhow traffic matching specific criteria is forwarded to backend Services.
This separation means that a platform team can provision a Gateway once, and multiple application teams can independently attach their routing rules without coordinating with each other or needing cluster-level permissions.
Key Differences from Ingress
| Feature | Ingress | Gateway API |
|---|---|---|
| Resource model | Single resource | GatewayClass + Gateway + Route |
| Role separation | None (all-in-one) | Infrastructure, operations, application |
| Cross-namespace routing | Not supported | Native support via parentRefs |
| Traffic splitting | Annotations only | First-class weighted routing |
| Header matching | Limited annotations | Native header/query param matching |
| Request mirroring | Annotations only | Native filter support |
| Protocol support | HTTP/HTTPS only | HTTP, gRPC, TCP, TLS, UDP |
| Status reporting | Minimal | Rich status conditions |
The Resource Hierarchy
GatewayClass (infrastructure provider)
βββ Gateway (cluster operator)
βββ HTTPRoute (app team A)
βββ HTTPRoute (app team B)
βββ GRPCRoute (app team C)
A GatewayClass is cluster-scoped. A Gateway is namespace-scoped but can reference routes from other namespaces (if allowed). HTTPRoutes are namespace-scoped and can attach to Gateways in the same or different namespaces.
Architecture and Design Patterns
GatewayClass: The Foundation
A GatewayClass defines the implementation that backs the Gateway. Most ingress controller vendors provide a GatewayClass resource as part of their installation:
# Provided by your ingress controller vendor
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: envoy-gateway
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controllerGateway: The Infrastructure Layer
A Gateway resource requests a load balancer and defines the entry points for traffic:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: main-gateway
namespace: infra
spec:
gatewayClassName: envoy-gateway
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All # Allow routes from any namespace
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: wildcard-tls
namespace: infra
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: "true"The allowedRoutes field controls which namespaces can attach routes to this Gateway. This is a critical security feature that prevents unauthorized teams from hijacking traffic.
HTTPRoute: The Application Layer
HTTPRoutes define how traffic matching specific criteria is routed to backend Services:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: app-team-a
spec:
parentRefs:
- name: main-gateway
namespace: infra
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080
weight: 90
- name: api-service-canary
port: 8080
weight: 10
- matches:
- path:
type: PathPrefix
value: /static
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Cache-Enabled
value: "true"
backendRefs:
- name: static-files
port: 80Step-by-Step Implementation
Installing a Gateway API-Compatible Controller
Most major ingress controllers now support Gateway API. Here is how to install Envoy Gateway:
# Install Envoy Gateway
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.1.0 \
-n envoy-gateway-system \
--create-namespace
# Verify installation
kubectl get pods -n envoy-gateway-systemOr NGINX Gateway Fabric:
helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
--create-namespace -n nginx-gatewayCreating Your First Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: eg # Envoy Gateway class name
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Samekubectl apply -f gateway.yaml
# Check Gateway status
kubectl get gateway my-gateway
kubectl describe gateway my-gatewayMigrating from Ingress to HTTPRoute
Before (Ingress):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
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-service
port:
number: 8080
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80After (Gateway API):
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app-route
spec:
parentRefs:
- name: my-gateway
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080
weight: 90
- name: api-service-canary
port: 8080
weight: 10
- matches:
- path:
type: PathPrefix
value: /web
backendRefs:
- name: web-service
port: 80Notice how traffic splitting (canary deployment) is expressed as weighted backendRefs rather than vendor-specific annotations.
Real-World Use Cases
Canary Deployments with Traffic Splitting
Gateway API's weighted routing makes canary deployments straightforward:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-canary
spec:
parentRefs:
- name: main-gateway
hostnames:
- "api.example.com"
rules:
- backendRefs:
- name: api-stable
port: 8080
weight: 95
- name: api-canary
port: 8080
weight: 5Increase the canary weight gradually as confidence grows, then promote by updating the stable service and removing the canary.
Header-Based Routing for A/B Testing
Route users to different versions based on request headers:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ab-test-route
spec:
parentRefs:
- name: main-gateway
hostnames:
- "app.example.com"
rules:
- matches:
- headers:
- name: X-User-Group
value: beta
backendRefs:
- name: app-beta
port: 8080
- backendRefs:
- name: app-stable
port: 8080Cross-Namespace Routing
Application teams can route traffic to services in different namespaces:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: frontend-route
namespace: frontend-team
spec:
parentRefs:
- name: shared-gateway
namespace: platform
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: frontend-service
port: 80
namespace: frontend-team
- matches:
- path:
type: PathPrefix
value: /api/users
backendRefs:
- name: user-service
port: 8080
namespace: backend-teamgRPC Routing
Gateway API has first-class support for gRPC through GRPCRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: grpc-route
spec:
parentRefs:
- name: main-gateway
hostnames:
- "grpc.example.com"
rules:
- matches:
- method:
service: myapp.UserService
method: GetUser
backendRefs:
- name: user-grpc-service
port: 50051Best Practices for Production
-
Start with a single Gateway β Use one Gateway per cluster or environment. Multiple Gateways create multiple load balancers, which increase cost and complexity.
-
Use namespace selectors for security β Configure
allowedRoutes.namespacesto restrict which teams can attach routes. Use label selectors for fine-grained control. -
Implement ReferenceGrants for cross-namespace access β When a route in namespace A needs to reference a service in namespace B, create a ReferenceGrant in namespace B to allow the cross-namespace reference.
-
Use Gateway infrastructure annotations β Annotate your Gateway with cloud-provider-specific annotations to configure load balancer type, IP address allocation, and other infrastructure details.
-
Monitor Gateway API status conditions β Check
kubectl get httproute -o yamlto see status conditions that indicate whether routes are accepted and programmed. -
Version your route configurations β Use Git to manage HTTPRoute configurations and deploy them through CI/CD. Treat routing rules as code.
-
Test with Gateway API conformance tests β The Gateway API project provides conformance tests that verify your implementation behaves correctly.
-
Plan your TLS strategy β Decide whether TLS termination happens at the Gateway or at the backend Service. Use
backendTLSfor end-to-end encryption when needed.
Common Pitfalls and Solutions
| Pitfall | Impact | Solution |
|---|---|---|
| Route not attached to Gateway | 404 errors | Check parentRefs and allowedRoutes namespace configuration |
| Cross-namespace reference rejected | Route shows "RefNotPermitted" status | Create a ReferenceGrant in the target namespace |
| Gateway stuck in "Pending" | No load balancer provisioned | Verify GatewayClass controller is running |
| TLS certificate not found | Gateway listener not programmed | Ensure Secret exists in the correct namespace |
| Traffic not splitting evenly | Weighted routing not working | Verify backend service ports match route port definitions |
| Status not updating | Cannot debug route issues | Check controller logs for reconciliation errors |
Performance Optimization
Gateway API implementations are optimized for performance, but there are configuration choices that affect throughput:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: high-perf-gateway
annotations:
# Envoy Gateway specific tuning
gateway.envoyproxy.io/connection-buffer-limit: "32768"
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: AllFor high-traffic deployments, consider:
- Using connection draining during deployments
- Configuring appropriate timeouts on HTTPRoutes
- Enabling HTTP/2 or HTTP/3 for improved multiplexing
- Using backend connection pooling through Gateway infrastructure annotations
Comparison with Alternatives
| Feature | Gateway API | Ingress | Service Mesh (Istio) | Traefik CRD |
|---|---|---|---|---|
| Standard | Yes (K8s SIG) | Yes (K8s) | No (vendor-specific) | No (vendor-specific) |
| Role-based design | Yes | No | Partial | No |
| Traffic splitting | Native | Annotations | Native | Native |
| Cross-namespace | Native | No | Yes | Yes |
| gRPC support | Native | No | Native | Native |
| TCP/UDP | Native | No | Yes | Yes |
| mTLS | Backend TLS | No | Native | Plugin |
| Complexity | Medium | Low | High | Medium |
| Vendor lock-in | None | None | High | Medium |
Gateway API is the right choice for most teams. Service meshes like Istio are appropriate when you need advanced features like mTLS between services, circuit breaking, and distributed tracing at the network level.
Advanced Patterns
Traffic Mirroring
Mirror production traffic to a canary deployment for testing without affecting users:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: mirror-route
spec:
parentRefs:
- name: main-gateway
rules:
- backendRefs:
- name: api-stable
port: 8080
filters:
- type: RequestMirror
requestMirror:
backendRef:
name: api-canary
port: 8080URL Rewriting
Transform request URLs before forwarding to backends:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: rewrite-route
spec:
parentRefs:
- name: main-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /old-api
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /v2
backendRefs:
- name: api-v2
port: 8080Request Redirects
Redirect HTTP to HTTPS or redirect old paths to new paths:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: https-redirect
spec:
parentRefs:
- name: main-gateway
sectionName: http
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301Testing Strategies
Validate Gateway API resources before deploying to production:
# Install Gateway API conformance tests
go test ./conformance/... -args \
-gateway-class=envoy-gateway \
-supported-features=HTTPRoute,HTTPRoutePathRedirect
# Test route matching
kubectl apply -f test-routes.yaml
kubectl get httproute -o yaml
# Verify traffic routing with curl
curl -H "Host: app.example.com" http://GATEWAY_IP/api/v1/users
curl -H "Host: app.example.com" -H "X-User-Group: beta" http://GATEWAY_IP/Use the Gateway API status conditions to debug route attachment issues:
kubectl describe httproute app-route
# Check "RouteStatus" section for "Accepted" conditionsFuture Outlook
Gateway API is actively evolving with new features and protocol support. Recent additions include:
- GRPCRoute (GA) β First-class gRPC routing
- TCPRoute / TLSRoute / UDPRoute β Support for non-HTTP protocols
- Backend TLS Policy β End-to-end encryption between Gateway and backends
- Gateway API Mesh β Extending Gateway API concepts to service mesh (GAMMA initiative)
The GAMMA (Gateway API for Mesh Management and Administration) initiative aims to unify ingress and service mesh routing under the Gateway API. This means the same HTTPRoute resources you use for ingress will work for east-west traffic within the mesh.
The long-term vision is that Gateway API becomes the single, standard API for all Kubernetes networkingβnorth-south (ingress), east-west (mesh), and cross-cluster (multi-cluster). Investing in Gateway API today positions your infrastructure for this future.
Gateway API Adoption Strategy
Migrate from Ingress to Gateway API incrementally. Start by installing the Gateway API CRDs and a compatible controller in your cluster. Create a Gateway resource for your ingress class and convert one Ingress resource at a time to an HTTPRoute. Use the Gateway API's parentRefs to control which routes attach to which gateways, enabling multi-team gateway sharing. Monitor the transition by running both Ingress and Gateway API resources in parallel during migration. Once all routes are converted, remove the Ingress resources and the legacy ingress controller.
Gateway API Multi-tenancy
Implement multi-tenancy with Gateway API using Gateway resources per team or namespace. Each team can create their own HTTPRoute resources that reference shared Gateway infrastructure. Use ReferenceGrants to allow cross-namespace references securely. Implement rate limiting and traffic policies at the Gateway level to prevent one tenant from monopolizing resources. Use parentRefs with namespace selectors to control which routes attach to which gateways. Monitor per-tenant traffic using metrics labels derived from Gateway API metadata.
Conclusion
Gateway API is the official successor to Kubernetes Ingress, offering a richer, more expressive, and role-based approach to traffic routing. Its separation of concerns between infrastructure providers, cluster operators, and application developers makes it ideal for multi-team environments.
Key takeaways:
- Gateway API replaces Ingress with three resource types: GatewayClass, Gateway, and HTTPRoute
- Role-based design separates infrastructure (GatewayClass), operations (Gateway), and routing (HTTPRoute)
- First-class support for traffic splitting, header matching, request mirroring, and cross-namespace routing
- Supported by all major ingress controller implementations (NGINX, Envoy, Istio, Traefik, Kong)
- HTTPRoute supports weighted backendRefs for canary deployments without vendor annotations
- ReferenceGrant resources control cross-namespace service references
- GRPCRoute provides native gRPC routing support
- Status conditions on resources provide clear feedback on configuration errors
Start by installing a Gateway API-compatible controller, creating a Gateway resource, and migrating one Ingress resource at a time to HTTPRoute. The migration is straightforward, and the benefits in routing expressiveness and role separation are substantial.
For deeper exploration, see the Gateway API specification, the Gateway API conformance tests, and the Envoy Gateway documentation.