Configuration: HTTP map
This page documents the map directive. It creates variables whose values come from matching a source variable against a set of patterns. Mapped variables are available via {{variable}} interpolation in other directives.
map belongs in HTTP scope. Put it in an http * block, a host block, or a location block. It has no effect in the bare global { ... } block. The global block holds server-wide settings, not per-request HTTP directives. When you migrate from NGINX, http * is the counterpart of the NGINX http context.
Directives#
map#
map <source: string> <destination: string>- This directive specifies a source variable to match and a destination variable name to create. The nested block defines the mapping rules. Default: none
The destination variable name can be any identifier. Ferron stores it in the request variable map. You access it via {{name}} interpolation.
Block sub-directives#
| Sub-directive | Arguments | Description | Default |
|---|---|---|---|
default | <value: string> | The fallback value when no entry matches the source. | Empty string |
exact | <pattern: string> <result: string> | Exact string match, or wildcard match if the pattern contains *. | None |
regex | <pattern: string> <result: string> | Regular expression match. You can reference capture groups in the result as $1, $2, and so on | None |
If Ferron cannot resolve the source variable, it treats the source value as an empty string and uses the default value. Ferron compiles regex patterns at parse time. It rejects invalid patterns during validation. Ferron converts wildcard patterns (*) to regex internally.
Values can also contain variable interpolations ({{name}}) that Ferron resolves at runtime.
Block options (inside regex { ... })#
| Option | Arguments | Description | Default |
|---|---|---|---|
case_insensitive | <bool> | When true, Ferron matches the regular expression pattern case-insensitively. | false |
Configuration example:
http * {
map request.uri.path category {
default uncategorized
exact /api/* api
exact /blog/* blog
}
}Matching priority#
When Ferron evaluates a map block, it checks the entries in this order:
- Exact match: the source value equals the pattern string exactly.
- Wildcard match: the pattern contains
*which matches any characters (equivalent to.*in regex). The longest-matching wildcard wins. - Regex match: the first regular expression in declaration order that matches the source value.
- Default: the
defaultvalue, or an empty string if not specified.
Simple variable mapping#
http * {
map request.uri.path category {
default uncategorized
exact /api/* api
exact /blog/* blog
exact /docs docs
}
}
example.com {
location / {
proxy http://backend {
request_header X-Category "{{category}}"
}
}
}Requests to /api/users set category to api, requests to /blog/post set it to blog, and /docs sets it to docs. Everything else falls back to uncategorized. Ferron then passes the mapped variable to the backend as a header.
Regex with capture groups#
http * {
map request.uri.path user_id {
default ""
regex "^/users/([0-9]+)" "$1"
}
}A request to /users/42 sets user_id to 42. Capture groups from the regex are available as $1, $2, and so on in the result string. If the pattern has no capture groups or the group does not exist, Ferron keeps the reference literally (for example $1).
Case-insensitive matching#
http * {
map request.header.user_agent is_mobile {
default "0"
regex "mobile" "1" {
case_insensitive
}
regex "android" "1" {
case_insensitive
}
}
}The case_insensitive option applies to individual regex entries. Alternatively, you can use the inline (?i) flag in the pattern itself: regex "(?i)mobile" "1".
Map at host and location level#
You can define map blocks inside http * blocks, host blocks, and location blocks. They inherit from parent scopes using standard Ferron inheritance. Do not place map in the bare global { ... } block.
http * {
map request.uri.path site_section {
default default
exact /public/* public
}
}
example.com {
# Overrides the global map for this host
map request.uri.path site_section {
default example-default
exact /special/* special
}
location /admin {
# Overrides at location level
map request.uri.path site_section {
default admin
}
}
}When you define a map with the same destination variable at multiple levels, the innermost scope takes precedence. Ferron evaluates all maps with different destination variables.
Pipeline position#
Map evaluation runs after client IP resolution and before URL rewriting. This means mapped variables are available for use in rewrite patterns, proxy configuration, and other downstream directives.
For map interaction with rewriting, see URL rewriting.
Observability#
Trace spans#
The map stage sets the following attributes on its ferron.stage.map span:
| Attribute | Type | Description |
|---|---|---|
ferron.map.variable | string | The variable name that Ferron maps. |
ferron.map.edited | bool | Whether the mapping changed the variable value. |