Anything else may possibly cause unpredictable behaviour, including potential SIGSEGV.
It is important to note that the behaviour of if is not inconsistent, given two identical requests it will not randomly fail on one and work on the other, with proper testing and understanding ifs ‘’‘can’‘’ be used. The advice to use other directives where available still very much applies, though.
There are cases where you simply cannot avoid using an if, for example, if you need to test a variable which has no equivalent directive.
Use try_files if it suits your needs. Use the “return ...” or “rewrite ... last” in other cases. In some cases, it’s also possible to move ifs to server level (where it’s safe as only other rewrite module directives are allowed within it).
In some cases it may be good idea to use embedded scripting modules (embedded perl, or various NGINX 3rd Party Modules) to do the scripting.
Here are some examples which explain why if is evil. Don’t try this at home. You were warned.
# if inside location is evil.
In case you think you found an example which isn’t listed here - it’s a good idea to report it to the NGINX development mailing list.
Directive “if” is part of rewrite module which evaluates instructions imperatively. On the other hand, NGINX configuration in general is declarative. At some point due to users demand an attempt was made to enable some non-rewrite directives inside “if”, and this lead to situation we have now. It mostly works, but... see above.
Looks like the only correct fix would be to disable non-rewrite directives inside if completely. It would break many configuration out there though, so wasn’t done yet.
Please make sure you actually do understand how it works. Some basic idea may be found e.g. here.