skip to content

A Kubernetes Ingress rule requires a pathType. Explain the difference between Prefix, Exact and ImplementationSpecific, and how a request URL is matched against them.

level: middleimportance: must knowfreq 48%

answer

  1. Prefix = segment-wise, not startsWith
  2. /foo Prefix does NOT match /foobar
  3. Exact: case-sensitive, no trailing-slash mercy
  4. ImplementationSpecific = controller decides, regex lives here
  5. Exact > longest Prefix; YAML order irrelevant

basics

~20 s

Exact matches the whole URL path, case-sensitive, with no trailing-slash tolerance. Prefix matches on complete path segments split by /, so /foo matches /foo and /foo/bar but never /foobar. ImplementationSpecific hands matching to the controller, which may allow regexes. Exact wins over Prefix, longest prefix first.

solid answer

~50 s

`pathType` is required in `networking.k8s.io/v1` and has three values. - **`Exact`** — the request path must equal the value exactly, case-sensitively. `/foo` does not match `/foo/` or `/Foo`. - **`Prefix`** — matched **element-wise on `/`-separated segments**, which is the part people get wrong. `/foo` matches `/foo`, `/foo/`, `/foo/bar`; it does **not** match `/foobar`, because `foobar` is a different segment. `/` matches everything. Query strings are never part of matching. - **`ImplementationSpecific`** — semantics are delegated to the controller. This is how controllers expose regex paths and capture groups for rewrite annotations. It is not portable: the same object behaves differently under a different controller. When several paths match, `Exact` beats `Prefix`, and among prefixes the longest match wins; ordering in the YAML is irrelevant. Matching across hosts prefers the most specific host, so an exact host beats a wildcard host, and a rule with no host is a catch-all.

code

yaml · 28 lines
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop
spec:
  ingressClassName: nginx
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /healthz
            pathType: Exact
            backend:
              service:
                name: health
                port: {number: 80}
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api
                port: {number: 8080}
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port: {number: 80}

go deeper

for a junior

Know the three values and the headline rule: Exact is the whole path, Prefix is segment-based, ImplementationSpecific is up to the controller.

for a middle

Give the /foo versus /foobar example unprompted, know that trailing slashes and case matter for Exact, and state the Exact-then-longest-Prefix precedence.

for a senior

Add the merge behaviour across Ingress objects sharing a host, the rewrite gap, and why ImplementationSpecific regexes are a portability and security liability.

for a principal

Treat path ownership on shared hostnames as a governance question: who may claim which prefixes, how conflicts are detected, and whether the escape hatch of implementation-specific paths is permitted at all.

## Why pathType exists In the old `extensions/v1beta1` Ingress there was no `pathType`; the `path` string meant whatever the controller decided — sometimes a literal prefix, sometimes a regex. The same manifest routed differently on NGINX and on a cloud controller. `networking.k8s.io/v1` made `pathType` a **required** field precisely to nail down semantics, with `ImplementationSpecific` as the explicit escape hatch for behaviour that cannot be standardised. ## Exact The request path must be byte-identical to the configured value. Matching is case-sensitive, and there is no trailing-slash normalisation: `/foo` does not match `/foo/`. Query parameters and the fragment are not part of the path, so `/foo?x=1` still matches `Exact: /foo`. Use it for single endpoints where you want no chance of catching child paths — a health endpoint, a well-known URL, a single callback. ## Prefix — the segment rule This is the field that generates real interview follow-ups. A `Prefix` match is **not** a string `startsWith`. Both the configured path and the request path are split on `/` into elements, and the rule matches when the configured elements are a prefix of the request elements. Concrete consequences for `path: /foo, pathType: Prefix`: - `/foo` → match. - `/foo/` → match (the trailing empty element is ignored). - `/foo/bar` → match. - `/foobar` → **no match** — `foobar` is a distinct segment, even though the string starts with `/foo`. - `/FOO` → no match; matching is case-sensitive. A trailing slash on the configured path is ignored, so `/foo/` and `/foo` behave identically. The special value `/` with `Prefix` matches every path and is the idiomatic catch-all. This rule matters for security as much as convenience. Someone assuming string prefixes might expect `/admin` to also guard `/administration`; it does not, and reasoning about which paths a rule covers must be done in segments. ## ImplementationSpecific The controller decides. NGINX-family controllers commonly interpret the path as a regular expression when a regex-related annotation is present, which is what enables capture groups feeding `rewrite-target: /$2`. Cloud controllers may interpret it as their own load balancer's native path syntax, or simply treat it as `Prefix`. The cost is portability: an `ImplementationSpecific` path is meaningless without knowing the controller, cannot be validated by the API server, and can change behaviour on a controller upgrade. Treat it as a last resort, document the controller assumption next to it, and be aware that regex paths in a shared cluster expand the surface anyone with Ingress write access can influence. ## Match precedence across rules Given a request, the controller first selects a rule by host — most specific host wins, so an exact host beats a wildcard `*.example.com`, and a rule with no `host` acts as a catch-all for unmatched hostnames. Within that host, paths are evaluated as: `Exact` matches first, then `Prefix` matches with the **longest** matching path taking priority. Order in the manifest carries no meaning, and neither does the order of rules across separate Ingress objects for the same host — controllers merge them. Wildcard hosts follow DNS-style single-label rules: `*.example.com` matches `shop.example.com` but not bare `example.com` and not `a.b.example.com`. ## Common design mistakes 1. **Expecting a rewrite.** A `Prefix: /api` rule forwards the **full** path to the backend, including `/api`. Nothing is stripped. If the backend expects `/`, you need a rewrite — which in Ingress is a controller annotation, not a spec field. 2. **Overlapping prefixes across teams.** Because longest-prefix wins across merged Ingress objects for the same host, one team adding `/api/v2` silently takes traffic from another team's `/api`. Controllers often expose a stricter-conflict setting; without it, review shared hostnames. 3. **Using `Exact` for a browser-facing page** and then being surprised that the trailing-slash form 404s. 4. **Assuming case-insensitive matching**, which HTTP paths are not. 5. **Putting query parameters in the path**; they are never matched. ## Version note `pathType` is required in `networking.k8s.io/v1`, GA since Kubernetes 1.19. Objects converted from `extensions/v1beta1` (removed in 1.22) default to `ImplementationSpecific`, which is why old manifests often carry that value without intent — worth auditing and changing to `Prefix` or `Exact` where the behaviour allows.

  • With `path: /api, pathType: Prefix`, what path does the backend Service actually receive?
    The full original path, `/api/orders` and all — Ingress does not strip the matched prefix. If the backend serves its routes at `/orders`, you must add a rewrite, and rewriting is not part of the Ingress spec, so it is a controller annotation such as `nginx.ingress.kubernetes.io/rewrite-target`, usually paired with an `ImplementationSpecific` regex path with capture groups.
  • Two Ingress objects for the same host define `/api` and `/api/v2`, both Prefix. Which serves a request for `/api/v2/orders`?
    The `/api/v2` rule, because the longest matching prefix wins and controllers merge rules from multiple Ingress objects for the same host. Manifest order and object creation order do not matter for this. It is a real multi-tenancy hazard: adding a longer prefix silently takes traffic from an existing rule, so shared hostnames deserve review or a controller setting that flags conflicts.

saying these in an interview costs you the question

  • Treating Prefix as a plain string startsWith, so expecting /foo to match /foobar
  • Expecting the matched prefix to be stripped before the request reaches the backend
  • Assuming path matching is case-insensitive
  • Believing the order of paths in the YAML determines which one wins
  • Thinking query parameters participate in path matching

context