What order do location directives fire in?
-
Neither the existing answers nor the official nginx documentation explain how the location selection algorithm works when nested location blocks are present in the configuration. A detailed explanation of this algorithm can be found in this ServerFault Q/A.Ivan Shatsky– Ivan Shatsky2025-07-02 19:22:36 +00:00Commented Jul 2 at 19:22
4 Answers
From the HTTP core module docs:
- Directives with the "=" prefix that match the query exactly. If found, searching stops.
- All remaining directives with conventional strings. If this match used the "^~" prefix, searching stops.
- Regular expressions, in the order they are defined in the configuration file.
- If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.
Example from the documentation:
location = / {
# matches the query / only.
[ configuration A ]
}
location / {
# matches any query, since all queries begin with /, but regular
# expressions and any longer conventional blocks will be
# matched first.
[ configuration B ]
}
location /documents/ {
# matches any query beginning with /documents/ and continues searching,
# so regular expressions will be checked. This will be matched only if
# regular expressions don't find a match.
[ configuration C ]
}
location ^~ /images/ {
# matches any query beginning with /images/ and halts searching,
# so regular expressions will not be checked.
[ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
# matches any request ending in gif, jpg, or jpeg. However, all
# requests to the /images/ directory will be handled by
# Configuration D.
[ configuration E ]
}
If it's still confusing, here's a longer explanation.
6 Comments
/ and /documents/ rules match the request /documents/index.html, but the latter rule takes precedence since it's the longest rule.location /test/ will be magically half-used (proxy_pass, add_header etc will be evaluated, but setting variables will not) over location ~* ^/test$ for requests to /test and will return a redirect, only location = /test can overrule this.proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, or grpc_pass directives should be used as the location content handler to trigger this behavior. However, the fact that it cannot be overridden with location ~ ^/test$ { ... } surprises me as well. This is probably due to the fact that "exact match" locations are checked first, while regex locations are evaluated last — after all prefix locations have been tested.add_header will be evaluated, but setting variables will not"?It fires in this order.
=(exactly)
location = /path
^~(forward match)
location ^~ /path
~,~*(regular expression case sensitive and insensitive)
location ~ /path/,location ~* .(jpg|png|bmp)
/
location /path
4 Comments
location = /path/, and the others should include start and end modifiers (^ and $)Locations are evaluated in this order:
location = /path/file.ext {}Exact matchlocation ^~ /path/ {}Priority prefix match -> longest firstlocation ~ /Paths?/ {}(case-sensitive regexp) andlocation ~* /paths?/ {}(case-insensitive regexp) -> first matchlocation /path/ {}Prefix match -> longest first
The priority prefix match (number 2) is exactly as the common prefix match (number 4), but has priority over any regexp.
For both prefix matche types the longest match wins.
Case-sensitive and case-insensitive have the same priority. Evaluation stops at the first matching rule.
Documentation says that all prefix rules are evaluated before any regexp, but if one regexp matches then no standard prefix rule is used. That's a little bit confusing and does not change anything for the priority order reported above.
Comments
Nginx configuration is declarative and has very little in common with imperative programming languages (with the notable exception of directives from the rewrite module, which are internally translated into pseudo-code and executed during each request's processing). Everything else is compiled into the internal configuration representation. There is no such thing as a "location directive firing order".
There is, however, a well-defined location selection algorithm. Only the most upvoted answer on this page attempts to describe that algorithm, although it still omits several important technical details. Other answers mistakenly try to describe a non-existent "evaluation order".
There are only three types of location blocks:
- Exact match
- Prefix match
- Regular expression (regex) match
The location selection algorithm works as follows:
Exact match:
If a matching "exact match" location (declared using the=modifier) exists, it is selected immediately to handle the request. Otherwise, the algorithm proceeds to step 2.Prefix match:
The longest matching prefix location is identified. All prefix locations (both with and without the^~modifier) are internally stored in a data structure known as a red-black tree when the configuration is compiled at nginx startup. The longest matching prefix is found using this binary tree traversal with time complexityO(log n). If the longest matching prefix has the^~modifier, it is selected to handle the request. Otherwise, proceed to step 3.Regex match:
All regular expression locations, both case-sensitive (defined using the~modifier) and case-insensitive (defined using the~*modifier) are checked sequentially in the order they appear in the configuration. This is the only case where declaration order matters. The first regex location that matches the request URI is selected to handle the request. If no regex matches are found, the longest matching prefix location from step 2 is used.
As you can see, the concept of "order" only applies to step 3, where regex locations are tested in declaration order. If no exact match location is found, nginx will search for the longest matching prefix location, regardless of whether any regex locations are defined. And if the best matching prefix location does not have the ^~ modifier, nginx will try to match the request that will eventually be processed by that location against every defined regex location pattern. This can be a performance concern when many are defined, as regex matching is relatively expensive compared to every other operation described above.
Nginx was originally developed for high-load systems, and this algorithm is designed to help write efficient configurations by minimizing the number of regex pattern-matching operations. Even more control is possible by using nested locations. Typically, they are used to isolate a group of nested regex locations under the outer prefix location.
Things get significantly more complicated when the nested location blocks are involved, and even the official nginx documentation does not fully describe how location selection works in these cases. I have a separate answer on ServerFault that explains the location selection algorithm when nested locations are used.