Skip to main content

NGINX / Server Setup

NGINX Array Variables: Split, Map, and Join Data

by ,


We have by far the largest RPM repository with NGINX module packages and VMODs for Varnish. If you want to install NGINX, Varnish, and lots of useful performance/security software with smooth yum upgrades for production use, this is the repository for you.
Active subscription is required.

Standard NGINX configuration handles strings well, but it lacks native support for lists of values. If you need to split a comma-separated query parameter into individual items, transform each one, and reassemble them, you know the limitations. The NGINX array variables module solves this by introducing array-typed variables directly into your config.

In this article, you will learn how to install, configure, and use the NGINX array variables module. You will see practical examples for building dynamic SQL conditions, transforming user input, and processing delimited data — all without external scripts.

What Are NGINX Array Variables?

The array-var-nginx-module, created by Yichun Zhang (author of OpenResty), adds array-typed variables to NGINX. Under the hood, it stores binary pointers to NGINX’s internal ngx_array_t C data structure within regular string variables.

This means you can perform operations common in programming languages but traditionally impossible in NGINX config files:

  • Split a delimited string into individual elements
  • Map a transformation to every element in an array
  • Join array elements back into a single string
  • Apply NGINX directives to each element using higher-order operations

The module provides four directives: array_split, array_join, array_map, and array_map_op. It also exposes the $array_it iterator variable for use within array_map templates. Together, these tools bring functional programming concepts to your NGINX configuration.

Why Use This Module?

You might wonder why you would process arrays at the NGINX level. There are several compelling reasons:

  • Reduced backend load: Transform and validate data before it reaches your application
  • Dynamic query construction: Build SQL WHERE clauses from URL parameters
  • Input sanitization at the edge: Escape user-supplied values before they reach your backend
  • URL parameter manipulation: Split, transform, and reconstruct query strings for routing
  • Logging flexibility: Decompose complex parameters for structured logging

However, for complex logic beyond split/map/join operations, consider the Lua NGINX module instead. It provides full scripting capabilities within NGINX.

Installation

The NGINX array variables module depends on the NGINX Development Kit (NDK). This framework provides the underlying infrastructure for variable manipulation. Both modules must be installed and loaded.

RHEL, CentOS, AlmaLinux, Rocky Linux, and Amazon Linux

First, enable the GetPageSpeed repository. Then install the module package:

sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-array-var

The NDK dependency is installed automatically. After installation, add these lines at the very top of /etc/nginx/nginx.conf, before the events block:

load_module modules/ndk_http_module.so;
load_module modules/ngx_http_array_var_module.so;

Important: The NDK module must load before the array-var module. If you reverse the order, NGINX fails to start with an undefined symbol: ndk_set_var_value error.

Debian and Ubuntu

First, set up the GetPageSpeed APT repository, then install:

sudo apt-get update
sudo apt-get install nginx-module-array-var

On Debian/Ubuntu, the package handles module loading automatically. No load_module directive is needed.

You can find more details on the RPM module page or the APT module page.

Verify the Installation

After adding the load_module directives (on RHEL-based systems), test your config:

sudo nginx -t

If the test passes, reload NGINX:

sudo systemctl reload nginx

Directive Reference

The NGINX array variables module provides four directives. All are valid in the http, server, and location contexts (including if blocks).

array_split

Syntax: array_split <separator> <subject> [max_items] [to=$target_variable]

Default: none

Context: http, server, location

Splits the string in subject by the separator and stores the result as an array variable.

Basic usage — split in-place (the source variable becomes an array):

array_split "," $arg_names;

With target variable — store the result in a different variable:

array_split "," $arg_names to=$names_array;

With max items — limit the number of resulting elements:

array_split "," $arg_data 3 to=$items;

When you set a maximum, the last element contains the unsplit remainder. Splitting "a,b,c,d,e" with max 3 produces: a, b, and c,d,e.

Empty separator — splits the string into individual characters:

array_split "" $arg_word to=$chars;

array_join

Syntax: array_join <separator> $array_var [to=$target_variable]

Default: none

Context: http, server, location

Joins all elements of an array variable into a single string. It uses the specified separator between elements. This directive converts an array back into a regular string for use with echo, return, or proxy_set_header.

In-place join — the array variable becomes a string:

array_join " + " $names;

With target variable — preserve the original array:

array_join " | " $names to=$result;

array_map

Syntax: array_map <template> $array_var [to=$new_array_var]

Default: none

Context: http, server, location

Applies a string template to each element of an array. Inside the template, use $array_it to reference the current element.

In-place mapping — modifies the array directly:

array_map "[$array_it]" $names;

This wraps each element in square brackets. If $names contained Alice, Bob, Charlie, it becomes [Alice], [Bob], [Charlie].

With target variable — keep the original array unchanged:

array_map "item=$array_it" $names to=$formatted;

You can use any NGINX variables inside the template alongside $array_it:

set $prefix "user";
array_map "${prefix}_$array_it" $names;

array_map_op

Syntax: array_map_op <directive> $array_var [to=$new_array_var]

Default: none

Context: http, server, location

This is a higher-order directive. It applies another NGINX directive to each element of an array. The directive must use the NDK’s set_var interface. In practice, this means directives from the set-misc module:

  • set_quote_sql_str — escapes for safe SQL string literals
  • set_quote_pgsql_str — escapes for PostgreSQL
  • set_quote_json_str — escapes for JSON strings
  • set_escape_uri — URL-encodes values
  • set_unescape_uri — URL-decodes values
  • set_encode_base64 / set_decode_base64 — Base64 encoding
  • set_sha1 / set_md5 — hash computation

In-place operation:

array_map_op set_quote_sql_str $names;

With target variable:

array_map_op set_escape_uri $names to=$escaped_names;

To use array_map_op, install the module that provides your target directive. For example, install nginx-module-set-misc:

sudo dnf install nginx-module-set-misc

Then load it in your nginx.conf (after NDK):

load_module modules/ndk_http_module.so;
load_module modules/ngx_http_set_misc_module.so;
load_module modules/ngx_http_array_var_module.so;

The $array_it Variable

The $array_it variable is a special iterator. It is only meaningful inside an array_map template. It references the current array element during iteration. Outside of array_map, this variable is empty.

Practical Use Cases

Now that you understand each directive, let us walk through scenarios where NGINX array variables prove most useful.

Building Dynamic SQL Conditions

One of the most powerful applications is constructing safe SQL WHERE clauses. You can build these from user-supplied comma-separated parameters. This works well when NGINX talks directly to a database backend.

location /api/search {
    # Split the comma-separated "tags" parameter
    array_split ',' $arg_tags to=$tags;

    # Escape each tag for safe SQL inclusion
    array_map_op set_quote_sql_str $tags;

    # Wrap each escaped tag in a condition
    array_map "tag = $array_it" $tags;

    # Join with OR to form the WHERE clause
    array_join ' OR ' $tags to=$where_clause;

    # Pass to backend via header
    proxy_set_header X-SQL-Filter $where_clause;
    proxy_pass http://backend;
}

A request to /api/search?tags=nginx,performance,security generates:

tag = 'nginx' OR tag = 'performance' OR tag = 'security'

Each value is properly quoted by set_quote_sql_str. This prevents SQL injection attacks. A malicious input like nginx'; DROP TABLE-- is safely escaped to 'nginx\'; DROP TABLE--'.

Processing CSV Data from Query Parameters

Suppose your application receives file paths as a comma-separated parameter. You can split, transform, and reassemble this data:

location /files {
    array_split ',' $arg_files to=$file_list;
    array_map "/data/$array_it" $file_list;
    array_join '|' $file_list to=$internal_paths;

    proxy_set_header X-File-Paths $internal_paths;
    proxy_pass http://file-server;
}

A request to /files?files=report.pdf,data.csv,image.png produces:

/data/report.pdf|/data/data.csv|/data/image.png

URL Encoding Array Elements

When passing array values as URL parameters to an upstream, use set_escape_uri for proper encoding:

location /redirect {
    array_split ',' $arg_params to=$params;
    array_map_op set_escape_uri $params;
    array_map "p=$array_it" $params;
    array_join '&' $params to=$qs;

    return 302 /destination?$qs;
}

Note: Avoid using $query_string as a target variable name. It is a built-in NGINX variable and cannot be overwritten.

Limiting Split Results

Sometimes you only need the first few items from a delimited string. The max_items parameter handles this:

location /preview {
    # Take first 3 tags only
    array_split ',' $arg_tags 3 to=$preview_tags;
    array_join ', ' $preview_tags to=$display;
    add_header X-Preview-Tags $display;
    proxy_pass http://backend;
}

With ?tags=a,b,c,d,e,f, only three elements are produced: a, b, and c,d,e,f. The last element holds all remaining items. This prevents large arrays from consuming memory.

Performance Considerations

The NGINX array variables module operates entirely in memory. It runs within NGINX’s request processing cycle. Therefore, the performance impact is minimal for typical use cases. Keep these points in mind:

  • Array size: Each element allocates memory from the request pool. Very large arrays (thousands of elements) increase memory per request.
  • map_op overhead: array_map_op calls another directive’s handler for each element. Expensive directives like set_sha1 multiply in cost.
  • Avoid unnecessary splits: Only split when you need individual elements. If you just pass a comma-separated string through, do not split it.

For high-traffic servers, set a reasonable max_items limit to cap resource usage.

Troubleshooting

“undefined symbol: ndk_set_var_value”

This error means the NDK module is not loaded before array-var. Fix the order:

load_module modules/ndk_http_module.so;       # Must be first
load_module modules/ngx_http_array_var_module.so;  # After NDK

“directive not found or does not use ndk_set_var_value”

This array_map_op error means the directive you specified either does not exist or is not NDK-compatible. Verify that:

  1. The module providing the directive is installed and loaded
  2. The directive supports the NDK set_var interface

Most set-misc module directives are compatible. Standard NGINX directives like set or return are not.

“invalid array variable value”

This error from array_join, array_map, or array_map_op means you passed a regular string instead of an array. Only variables created by array_split or array_map (with to=) hold valid array types. Ensure you call array_split before join or map.

Empty or Missing Output

If array_join produces an empty result, check that:

  1. The source query parameter contains data (test with echo $arg_paramname)
  2. The array_split separator matches the delimiter in the data
  3. You are not overwriting the variable between operations

You can use the NGINX echo module for debugging variable values during development.

Security Best Practices

When processing user input with NGINX array variables, follow these guidelines:

  • Always escape before SQL usage: Use array_map_op set_quote_sql_str for any SQL fragment built from user data
  • Limit array sizes: Use max_items to prevent denial-of-service attacks with thousands of values
  • Validate input early: Use NGINX’s map directive to reject invalid input before splitting
  • Do not expose internals: Avoid returning raw array-joined content to clients

For additional NGINX security hardening, see our guide on security headers.

Comparison with Alternative Approaches

The NGINX array variables module is not the only way to process lists. Here is how it compares:

Approach Pros Cons
array-var module Lightweight, no scripting, fast Limited to split/map/join
Lua NGINX module Full language, conditionals, loops Heavier dependency
NGINX map directive Built-in, no extra modules Cannot iterate dynamic lists
Backend processing Most flexible Adds latency, more backend load

For simple list processing, NGINX array variables strike the best balance. For complex logic with conditionals or loops, choose the Lua module.

Conclusion

The NGINX array variables module fills an important gap in NGINX’s config language. With four directives — array_split, array_join, array_map, and array_map_op — you can split delimited strings, transform each element, and reassemble them.

This module is especially useful for system administrators who need to process query parameters, build dynamic SQL conditions, or manipulate URL components. Combined with the set-misc module, it provides a powerful yet lightweight data transformation toolkit.

The source code is available on GitHub. Pre-built packages are available from the GetPageSpeed repository for all major Linux distributions.

D

Danila Vershinin

Founder & Lead Engineer

NGINX configuration and optimizationLinux system administrationWeb performance engineering

10+ years NGINX experience • Maintainer of GetPageSpeed RPM repository • Contributor to open-source NGINX modules

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.