How Nginx Chooses a location Block
Inside a server block, location directives map URI paths to specific handling logic — where to look for files, which upstream to proxy to, or which headers to set. Nginx doesn't evaluate location blocks top-to-bottom like a firewall ruleset; instead it runs a two-phase algorithm: it first finds the longest matching prefix among all non-regex locations, then checks regex locations (~ and ~*) in the order they're written, and a regex match overrides the prefix match unless the prefix location was declared with the ^~ modifier to short-circuit regex checking entirely.
Cricket analogy: It's like a fielding captain first placing fielders by general zone (longest prefix, e.g. covers) before making a specific tactical regex-like adjustment such as a short leg for a particular batsman, unless the captain locks the field with a fixed plan (^~) that overrides further tweaks.
Prefix, Exact, and Regex Location Modifiers
The plain prefix form location /api/ { ... } matches any URI beginning with /api/ and Nginx keeps the longest such match found. location = /health { ... } requires an exact URI match with no trailing characters, which is the fastest possible match and commonly used for health-check endpoints. Case-sensitive regex uses ~ (location ~ \.php$ { ... }) while case-insensitive regex uses ~* (location ~* \.(jpg|png|gif)$ { ... }), and both are evaluated in source order the moment Nginx moves into the regex-matching phase, stopping at the first one that matches.
Cricket analogy: It's like the difference between a general fielding restriction for the powerplay overs (prefix match) versus a very specific no-ball review rule (exact match) that applies to one delivery only and gets checked instantly.
The ^~ Modifier and Common Pitfalls
The ^~ modifier tells Nginx: if this prefix location is the longest matching prefix, stop immediately and skip the regex-matching phase entirely, even if a later regex would otherwise match more specifically. This is frequently used to protect a directory like location ^~ /static/ { ... } from being intercepted by a broad regex rule such as location ~* \.(css|js)$ { ... } intended for a different purpose. A common pitfall is assuming location blocks are checked strictly top-to-bottom; forgetting the prefix-then-regex algorithm leads to configs where a seemingly 'later' rule silently wins.
Cricket analogy: It's like a captain declaring a fixed field placement for the death overs that no bowler-specific tactical adjustment is allowed to override, even if a normally sharper plan would apply later in the over.
server {
listen 80;
server_name example.com;
# Exact match wins instantly for health checks
location = /health {
return 200 "ok";
add_header Content-Type text/plain;
}
# ^~ stops regex matching from intercepting static assets
location ^~ /static/ {
root /var/www/example.com;
expires 30d;
}
# Case-insensitive regex for image extensions elsewhere
location ~* \.(jpg|jpeg|png|gif|ico)$ {
root /var/www/example.com;
expires 7d;
}
# Longest matching prefix for the API
location /api/ {
proxy_pass http://backend_upstream;
proxy_set_header Host $host;
}
}Reload with nginx -t && nginx -s reload after changing location blocks, and test ambiguous paths with curl -v http://localhost/static/app.js to confirm which block actually served the request via response headers or logging.
location blocks are NOT evaluated top-to-bottom. Nginx finds the longest matching prefix first, then only checks regex locations afterward — and a regex match beats a plain prefix match unless ^~ is used. Assuming file order controls precedence is one of the most common Nginx misconfiguration bugs in production.
- location blocks are matched by a longest-prefix-then-regex algorithm, not simple top-to-bottom order.
=performs an exact match and resolves fastest, ideal for health-check endpoints.- Plain prefix locations match the longest matching path;
^~stops Nginx from then checking regex locations. ~is case-sensitive regex,~*is case-insensitive regex, both evaluated in source order after prefix matching.- Regex locations override a plain prefix match unless the prefix location uses
^~. - Use
curl -vand access logs to empirically confirm which location actually handled an ambiguous request.
Practice what you learned
1. By default, which wins when both a plain prefix location and a regex location match the same request?
2. What does the `^~` modifier do?
3. Which location modifier is best suited for a lightweight health-check endpoint?
4. True or false: Nginx evaluates all location blocks strictly in the order they appear in the config file.
5. What is the difference between `~` and `~*` in a location directive?
Was this page helpful?
You May Also Like
Server Blocks Explained
How Nginx uses server blocks to host multiple independent sites on a single instance, and how listen and server_name determine which block answers a request.
Rewrites and Redirects
The difference between client-visible redirects (return) and internal URI rewrites (rewrite) in Nginx, plus the flags and pitfalls that cause loops and lost query strings.
Nginx Variables
How Nginx's dollar-sign variables are lazily computed per request, the difference between commonly confused ones like $uri and $request_uri, and how map builds custom derived variables cleanly.
Related Reading
Related Study Notes in DevOps
Browse all study notesAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics
DevOpsCI/CD Tools & Pipelines Study Notes
YAML · 37 topics