NGINX Ingress Controller Deprecation: Complete Migration Guide to Gateway API
The Cloud Native Computing Foundation (CNCF) has announced the deprecation of the NGINX Ingress Controller project, with official support ending in March 2026. This significant announcement marks a turning point in Kubernetes networking, as the community transitions from the traditional Ingress API to the more modern and powerful Gateway API. Organizations using NGINX Ingress Controller need to understand the implications and plan their migration to Gateway API implementations.
The NGINX Ingress Controller deprecation stems from several factors:
- Maintenance Burden: Keeping up with Kubernetes changes and security patches
- Limited Capabilities: The Ingress API’s limitations restrict advanced networking features
- Security Concerns: Ongoing security maintenance challenges
- Ecosystem Evolution: The industry’s shift toward Gateway API standards
- Resource Allocation: Community resources better focused on Gateway API implementations
- Deprecation Announced: September 2025
- Final Release: December 2025
- End of Life: March 2026
- Security Updates: Critical security patches through March 2026
- No New Features: No new feature development after deprecation announcement
The Gateway API represents the evolution of Kubernetes ingress, designed to address Ingress API limitations:
- Role-Oriented Design: Better separation of concerns across infrastructure, operators, and developers
- Advanced Routing: Header-based, query parameter, and method-based routing
- Cross-Namespace Support: Native support for routing across namespaces
- Type Safety: Better validation and error handling
- Extensibility: Standard extension points for vendor-specific features
- Portability: Works across different implementations and cloud providers
NGINX’s official Gateway API implementation, NGINX Gateway Fabric, provides a seamless path for NGINX Ingress users:
- NGINX Data Plane: Leverages proven NGINX technology
- Gateway API Compliant: Full implementation of Gateway API specifications
- Production Ready: Battle-tested in production environments
- Feature Parity: Many features from NGINX Ingress plus Gateway API enhancements
Document all current Ingress resources:
# List all Ingress resources across all namespaces
kubectl get ingress --all-namespaces -o wide
# Export configurations
kubectl get ingress --all-namespaces -o yaml > ingress-backup.yaml
# Identify annotations and custom configurations
kubectl get ingress --all-namespaces -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.namespace}{"\t"}{.metadata.annotations}{"\n"}{end}'
Identify dependencies and integrations:
- Monitoring: Prometheus, Grafana integrations
- Certificate Management: cert-manager, Let’s Encrypt
- Service Mesh: Istio, Linkerd integrations
- Custom Configurations: NGINX-specific annotations
- Load Balancing: Session affinity, health checks
Select a Gateway API implementation:
NGINX Gateway Fabric (Recommended for NGINX users):
- Direct migration path from NGINX Ingress
- Familiar NGINX features and behaviors
- Proven NGINX data plane
Istio Gateway:
- Full service mesh integration
- Advanced traffic management
- Multi-cluster support
Kong Gateway:
- Rich plugin ecosystem
- Advanced API management features
- Enterprise features
Envoy Gateway:
- Vendor-neutral implementation
- High performance
- CNCF project
# Add NGINX Gateway Fabric Helm repository
helm repo add nginx-gateway-fabric https://nginxinc.github.io/nginx-gateway-fabric-helm-charts
helm repo update
# Install NGINX Gateway Fabric
helm install nginx-gateway-fabric nginx-gateway-fabric/nginx-gateway-fabric \
--namespace nginx-gateway \
--create-namespace \
--set deployment.image.repository=nginx/nginx-gateway-fabric \
--set deployment.image.tag=latest
# Verify installation
kubectl get pods -n nginx-gateway
kubectl get gatewayclass
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: nginx-gateway
spec:
controllerName: gateway.nginx.org/gateway-controller
description: NGINX Gateway Fabric for production use
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: nginx-gateway
spec:
gatewayClassName: nginx-gateway
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
- name: https
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- name: production-tls-cert
namespace: cert-manager
Original Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
namespace: production
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- example.com
- www.example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
Converted HTTPRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web-route
namespace: production
spec:
parentRefs:
- name: production-gateway
namespace: nginx-gateway
hostnames:
- example.com
- www.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: web-service
port: 80
Many NGINX Ingress annotations have Gateway API equivalents:
Rate Limiting:
# NGINX Ingress Annotation
annotations:
nginx.ingress.kubernetes.io/limit-rps: "100"
# Gateway API Equivalent (using NGINX Gateway Fabric extension)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: rate-limited-route
spec:
parentRefs:
- name: production-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: ExtensionRef
extensionRef:
group: gateway.nginx.org
kind: RateLimitPolicy
name: rate-limit-policy
---
apiVersion: gateway.nginx.org/v1alpha1
kind: RateLimitPolicy
metadata:
name: rate-limit-policy
spec:
rate: 100
period: 1s
SSL Redirect:
# NGINX Ingress Annotation
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
# Gateway API - Use HTTPS listener with redirect filter
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: redirect-route
spec:
parentRefs:
- name: production-gateway
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
Path Rewriting:
# NGINX Ingress Annotation
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
# Gateway API Equivalent
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: rewrite-route
spec:
parentRefs:
- name: production-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /api/v1
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /v1
backendRefs:
- name: api-service
port: 8080
CORS Configuration:
# NGINX Ingress Annotations
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
# Gateway API Extension (NGINX Gateway Fabric)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: cors-route
spec:
parentRefs:
- name: production-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: ExtensionRef
extensionRef:
group: gateway.nginx.org
kind: CORSPolicy
name: cors-policy
---
apiVersion: gateway.nginx.org/v1alpha1
kind: CORSPolicy
metadata:
name: cors-policy
spec:
allowOrigins:
- "*"
allowMethods:
- GET
- POST
- PUT
- DELETE
allowHeaders:
- "*"
# NGINX Ingress Annotation
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "route"
nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
# Gateway API - Use Service with sessionAffinity
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
ports:
- port: 80
targetPort: 8080
# NGINX Ingress Canary Annotations
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
# Gateway API - Native Traffic Splitting
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
spec:
parentRefs:
- name: production-gateway
hostnames:
- example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: stable-service
port: 80
weight: 90
- name: canary-service
port: 80
weight: 10
# Gateway API provides native header matching
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-routing
spec:
parentRefs:
- name: production-gateway
rules:
- matches:
- headers:
- name: x-api-version
value: v2
backendRefs:
- name: api-v2-service
port: 8080
- matches:
- headers:
- name: x-api-version
value: v1
backendRefs:
- name: api-v1-service
port: 8080
- Parallel Deployment: Run both Ingress and Gateway API in parallel
- Traffic Splitting: Gradually shift traffic to Gateway API
- Monitoring: Compare metrics and performance
- Validation: Verify all functionality works correctly
# Gradual traffic migration
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: migration-route
spec:
parentRefs:
- name: production-gateway
rules:
- backendRefs:
# Keep old Ingress service initially
- name: ingress-service
port: 80
weight: 50
# Route to new Gateway API
- name: gateway-service
port: 80
weight: 50
- All routes working correctly
- TLS/SSL certificates functioning
- Load balancing working as expected
- Session affinity maintained (if used)
- Rate limiting applied correctly
- Monitoring and metrics collected
- Performance meets or exceeds previous setup
- Security policies enforced
cert-manager works seamlessly with Gateway API:
# Certificate resource (same as before)
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-tls
namespace: cert-manager
spec:
secretName: example-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- example.com
- www.example.com
# Reference in Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
spec:
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: example-tls
namespace: cert-manager
NGINX Gateway Fabric exposes Prometheus metrics:
apiVersion: v1
kind: Service
metadata:
name: nginx-gateway-metrics
namespace: nginx-gateway
labels:
app: nginx-gateway-fabric
spec:
ports:
- name: metrics
port: 9113
targetPort: 9113
selector:
app: nginx-gateway-fabric
Prometheus scraping configuration:
apiVersion: v1
kind: ServiceMonitor
metadata:
name: nginx-gateway-metrics
spec:
selector:
matchLabels:
app: nginx-gateway-fabric
endpoints:
- port: metrics
interval: 30s
Gateway API implementations provide structured logging compatible with existing log aggregation systems.
- Keep Ingress Resources: Don’t delete old Ingress resources immediately
- Traffic Redirection: Switch traffic back to Ingress controller
- Investigate Issues: Debug Gateway API configuration
- Fix and Retry: Correct issues and migrate again
# Switch traffic back to Ingress
kubectl scale deployment nginx-gateway-fabric --replicas=0 -n nginx-gateway
kubectl scale deployment ingress-nginx-controller --replicas=3 -n ingress-nginx
Organize Gateway resources logically:
# Infrastructure namespace for Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shared-gateway
namespace: infrastructure
# Application namespace for HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: applications
spec:
parentRefs:
- name: shared-gateway
namespace: infrastructure
Enable secure cross-namespace references:
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: allow-apps-to-infra
namespace: infrastructure
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: applications
to:
- group: gateway.networking.k8s.io
kind: Gateway
Migrate namespace by namespace:
- Start with non-critical applications
- Validate thoroughly
- Gradually migrate production workloads
- Monitor performance and stability
Problem: Extensive use of NGINX-specific annotations
Solution: Map annotations to Gateway API features or use implementation-specific extensions
Problem: Custom NGINX configurations not directly supported
Solution: Use Gateway API extension mechanisms or implementation-specific features
Problem: Tools expecting NGINX Ingress format
Solution: Update tools to support Gateway API or use translation layers
The deprecation of NGINX Ingress Controller marks an important transition in Kubernetes networking. While this change requires migration effort, it presents an opportunity to adopt more powerful, standardized, and future-proof networking solutions.
Key takeaways:
- Plan Early: Start migration planning well before March 2026
- Choose Implementation: Select a Gateway API implementation that fits your needs
- Gradual Migration: Migrate gradually with proper testing
- Leverage Advantages: Take advantage of Gateway API’s enhanced capabilities
- Stay Informed: Follow Gateway API development and best practices
The Gateway API ecosystem is mature, well-supported, and ready for production use. Organizations that migrate successfully will benefit from better security, more advanced features, and a more maintainable networking infrastructure.
The transition from NGINX Ingress Controller to Gateway API represents progress in Kubernetes networking, and with proper planning and execution, organizations can make this transition smoothly while gaining significant advantages in the process.
For more information about Gateway API migration, visit the official Gateway API documentation and NGINX Gateway Fabric repository.