Nginx Conditional Flags Explained: -f, -d, -e for File and Directory Checks in Rewrite Rules


2 views

When transitioning from Apache to Nginx, one of the trickiest parts is understanding how conditional checks work in rewrite rules. While Apache uses RewriteCond directives, Nginx handles these checks differently through if conditions with special flags.

Here are the primary file test operators in Nginx:

  • -f - Checks if the path exists and is a regular file
  • -d - Checks if the path exists and is a directory
  • -e - Checks if the path exists (either file or directory)
  • -x - Checks if the path exists and is executable

Let's examine some common use cases with code examples:

# Example 1: Check if file exists (-f)
if (-f $request_filename) {
    rewrite ^ /maintenance.html break;
}

# Example 2: Check if directory exists (-d)
if (-d $request_uri) {
    rewrite ^ /index.php?path=$request_uri;
}

# Example 3: Check if anything exists (-e)
if (-e $request_filename) {
    rewrite ^(.*)$ /index.php break;
}

While these conditionals are powerful, there are some key considerations:

  • Nginx evaluates if conditions during configuration, so they can impact performance if overused
  • The $request_filename variable contains the full filesystem path to the requested file
  • These checks follow symbolic links by default

For optimal performance and maintainability:

# Instead of multiple if conditions, consider:
location / {
    try_files $uri $uri/ /index.php?$args;
}

# Or for specific file checks:
location ~* \.php$ {
    if (!-f $request_filename) {
        return 404;
    }
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}

These flags are documented in Nginx's rewrite module documentation, though the explanation is quite brief. For more complex scenarios, you might need to combine multiple conditions or use map directives.


When transitioning from Apache to Nginx, one of the trickiest parts is understanding how conditional flags work in rewrite rules. These flags are essential for file and directory existence checks in Nginx configuration.

Nginx supports several test flags for the if directive:

# Check if regular file exists
if (-f $request_filename) { ... }

# Check if directory exists
if (-d $request_filename) { ... }

# Check if file/directory/symlink exists (-e)
if (-e $request_filename) { ... }

# Check if executable file exists (-x)
if (-x $request_filename) { ... }

Here's how you might use these in real configurations:

Basic File Existence Check

location / {
    if (-f $request_filename) {
        # Serve the file directly if it exists
        break;
    }
    rewrite ^ /index.php last;
}

Directory Protection

location /private/ {
    if (-d $request_filename) {
        return 403;
    }
}

While these conditional flags are powerful, Nginx's if directive has some limitations:

  • Nested if statements don't work as expected
  • If is context-dependent (works differently in server/location blocks)
  • Can impact performance if overused

The -e flag checks for existence of any file type (regular files, directories, symlinks). This makes it more versatile but slightly less precise than -f or -d:

# Example: Fallback to index.php if resource doesn't exist
if (!-e $request_filename) {
    rewrite ^ /index.php last;
}

For high-traffic sites, minimize if usage. Consider alternatives like:

location / {
    try_files $uri $uri/ /index.php?$args;
}

This achieves similar functionality to conditional checks but with better performance.

The official Nginx documentation doesn't explicitly list these flags. They're part of the rewrite module and work similarly to their counterparts in other languages.