An Ingress resource routes no traffic on its own: it describes rules something else has to translate into real configuration. That something, the Ingress Controller, has to be installed separately, and the choice between the two most common options, nginx-ingress and Traefik, comes down to a configuration model, not raw performance that’s rarely comparable in any meaningful way for most workloads.
nginx-ingress: a Kubernetes resource, an nginx configuration
nginx-ingress translates every Ingress resource into classic nginx configuration, regenerated and reloaded on every change. The configuration model stays nginx’s own, exposed via annotations on the Kubernetes resource:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/rate-limit: "100"
spec:
ingressClassName: nginx
rules:
- host: api.example.com
The advantage: a team already familiar with nginx finds a known vocabulary, and the project’s maturity (the most historically deployed) means abundant documentation for nearly every edge case. The structural limit: every configuration change triggers an nginx reload that can, under heavy traffic and many rules, cause brief drops in in-flight connections.
Traefik: native Kubernetes configuration, hot reload
Traefik starts from a different principle: configuration happens natively through Kubernetes Custom Resources (IngressRoute), with a hot reload that restarts no process at all.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: api-route
spec:
routes:
- match: Host(`api.example.com`)
kind: Rule
services:
- name: api-service
port: 80
middlewares:
- name: rate-limit
Hot reload eliminates the risk of a drop when a rule changes, a real benefit on a cluster with frequent deployments. The trade-off: IngressRoute is a Traefik-proprietary extension, not the standard Ingress resource, which reduces portability if the team ever wants to switch controllers without rewriting everything.
The real criterion: change frequency, not the brand
A cluster where routing rules change rarely (a handful of deployments per week) never feels nginx-ingress’s limit: reloads are too infrequent for their cost to matter. A cluster with very frequent deployments, preview environments continuously created and torn down (covered in the article on ephemeral preview environments per PR), directly feels Traefik’s hot-reload benefit, because the number of configuration changes itself becomes significant.
What doesn’t depend on the choice
Both controllers rely on MetalLB the same way in an on-premise context: the Ingress Controller runs behind a LoadBalancer Service, whether nginx-ingress or Traefik is driving it. The controller choice changes nothing about the network layer that exposes it to the outside world.
Takeaway
nginx-ingress and Traefik answer the same need through two opposite models: annotation-based configuration on a standard resource versus native Custom Resources with hot reload. The deciding criterion is the actual frequency of routing rule changes, not a brand preference or a raw performance comparison rarely relevant in practice. This choice, like the LoadBalancer service exposing it, gets made early in a Kubernetes migration.