Fluent CLI - Template Token Functions
Essential knowledge
Intended Audience:
Technical User
Author:
Marco Heuer
Changed on:
19 Oct 2026
Overview
Guide to using`lower()`, `upper()`, and `env()` functions inside Fluent CLI template tokens.Key points
- Three functions available:
`lower()`,`upper()`, and`env()`wrap a name inside the usual`[[...]]`token delimiters to transform or source a value. - Function parameters are token names, not literals — except for
`env()`, whose parameter is a literal environment variable name, not something looked up in the current token context. - Scope differs by function:
`lower()`/`upper()`resolve anywhere a token resolves (module config, workflow fragments, asset files);`env()`only resolves in module config values and errors if used elsewhere. `env()`is prefix-gated and fails closed: only environment variables matching`--env-prefix`(default`FLUENT_`) are readable, and a missing or disallowed reference aborts the command rather than silently installing the literal placeholder text.- No secret-store behaviour on the Fluent side:
`env()`keeps a secret out of the module config file and version control, but the resolved value still lands in plaintext in the uploaded workflow and the workflow log history, exactly like any other config value. - No nesting or chaining: functions can't be composed directly — resolve one function into a named template value first, then reference that value with a second function elsewhere.
Overview
Fluent CLI template tokens (`[[retailer.ref]]`, `[[account.id]]`, etc.) let a module config, workflow fragment, or asset file be written once and reused across accounts and retailers. Token functions extend this by transforming the resolved value before it's substituted — for example, converting a retailer reference to lowercase for a generated username.This removes the need to hand-edit config files per environment just to fix a case mismatch (e.g. a retailer ref stored as `ACME` but a username convention that expects `acme_admin`).Syntax
A token function wraps a standard token in a function call, inside the usual`[[...]]` delimiters:`[[functionName(token.name)]]`Function names are case-insensitive (`lower`, `LOWER`, and `Lower` are all treated the same). The token inside the parentheses must be a token name already available in the current context (profile values, or any `default:`/context-prefixed config key) — not a literal string.Supported Functions
lower()
Converts the resolved token value to lowercase.`[[lower(token.name)]]``{`"default:retailer.username": "[[lower(retailer.ref)]]_admin"
}If
`retailer.ref = "ACME"`, this resolves to `"acme_admin"`.upper()
Converts the resolved token value to uppercase.`[[upper(token.name)]]``{`"default:account.code": "[[upper(account.id)]]"
}If
`account.id = "acme"`, this resolves to `"ACME"`.env()
Resolves a module config value from a CI/CD environment variable, instead of a template token. This lets a pipeline inject per-environment or sensitive values (e.g. a webhook URL with an embedded auth token, sourced from a secrets manager) without editing the module config file for each run.`[[env(VAR_NAME)]]``{`"default:webhook.auth": "[[env(FLUENT_WEBHOOK_SECRET)]]"
}If the environment variable
`FLUENT_WEBHOOK_SECRET` is set when the command runs, this resolves to its value.`env()` only works in module config files — not inside workflow fragments or asset files directly (see Where Token Functions Work below) — and only for variables matching a required prefix, controlled by the `--env-prefix` flag on `module install`, `workflow merge`, and `workflowlog insert` (defaults to `FLUENT_`). A variable outside that prefix is treated as not set.Unlike `lower()`/`upper()`, an unresolved `env()` reference does not fall back to leaving the literal `[[env(...)]]` text in place — it fails the command outright, listing every missing or disallowed variable it found. This is deliberate: a credential field silently containing the literal placeholder text is worse than a command that refuses to run.Security note: resolution happens on the CLI side, before the config is merged/uploaded. The resolved value is still written in plaintext into the resulting workflow definition and into the workflow log's history, exactly like any other config value — `env()` only keeps the secret out of the module config file and version control, it does not add encryption or secret-store behaviour on the Fluent platform side.Where Token Functions Work
`lower()` and `upper()` are resolved by the same placeholder engine used everywhere Fluent CLI substitutes tokens, so they work consistently across:- Module config files (
`default:`,`workflow:`,`setting:`prefixed keys) - Workflow fragments merged via
`fluent workflow merge` - Asset files processed during module install (e.g. networks, locations)
`env()` is deliberately narrower: it only resolves while loading module config values. Writing `[[env(...)]]` directly inside a workflow fragment or asset file is a scope violation and raises an error, rather than silently leaving the text unresolved.How It Works
- Config values are resolved first. A value like
`"[[lower(retailer.ref)]]_admin"`in a config file is evaluated against the active profile's values (`retailer.ref`,`retailer.id`,`account.id`, etc.), producing`"acme_admin"`. - The result becomes a reusable template value. That resolved string is stored under its config key (e.g.
`retailer.username`), so other files can reference it with a plain token:`"username": "[[retailer.username]]"`→`"acme_admin"`. - Standard tokens and function tokens coexist freely:
`{`
"default:retailer.id": "[[retailer.id]]",
"default:retailer.username": "[[lower(retailer.ref)]]_admin"
} - Manual overrides always win. Any token or function result can be overridden by providing an explicit value in config:
`{`
"default:retailer.username": "custom_username"
}
Common Use Cases
Case Mismatch in Usernames
Problem: Retailer references are stored uppercase (`ACME`) but the username convention is lowercase (`acme_admin`).`{`"default:retailer.username": "[[lower(retailer.ref)]]_admin"
}The correct username is generated automatically — no per-environment edits needed.
Standardising Identifiers
Problem: An external system expects an uppercase integration code, but the internal retailer reference is mixed case.`{`"default:integration.code": "[[upper(retailer.ref)]]",
"default:api.endpoint": "https://api.example.com/[[lower(account.id)]]"
}
Injecting Secrets from a CI/CD Pipeline
Problem: A webhook URL needs an auth token pulled from a secrets manager at pipeline run time, without hardcoding it into the module config file.Solution: export the secret as an environment variable with the required prefix before running the install/merge command, and reference it in config:`{`"default:webhook.auth": "[[env(FLUENT_WEBHOOK_SECRET)]]"
}
`export FLUENT_WEBHOOK_SECRET="$(vault read -field=token secret/webhook)"`fluent module install ./my-module --config module.config.prod.jsonIf
`FLUENT_WEBHOOK_SECRET` isn't set when the command runs, the command fails with an error naming the missing variable, rather than installing the literal `[[env(FLUENT_WEBHOOK_SECRET)]]` text as the webhook's auth value.Examples
Complete User Configuration
1{
2 "default:retailer.username": "[[lower(retailer.ref)]]_admin",
3 "default:retailer.displayName": "[[retailer.name]] Administrator"
4}Integration Configuration
1{
2 "default:api.key": "[[upper(account.id)]]-[[upper(retailer.ref)]]",
3 "default:webhook.url": "https://webhooks.example.com/[[lower(retailer.ref)]]"
4}Limitations
- No nesting:
`[[upper(lower(value))]]`is not supported. - No chaining:
`[[value|lower|trim]]`is not supported. - String transformations only: values are coerced to a string before transforming.
- Unknown functions are left as-is:
`[[unknown(value)]]`remains the literal, unresolved token — it is not treated as an error. - Missing tokens are left as-is: if the referenced token has no resolved value, the whole
`[[functionName(token)]]`expression is left unchanged rather than substituted with an empty string.`env()`is the exception — see below. `env()`only works in module config files, requires the variable name to match the required prefix (`--env-prefix`, default`FLUENT_`), and fails the whole command (rather than leaving the literal text) if any referenced variable is missing or outside the prefix.
Troubleshooting
My Token Function Isn't Resolving — It's Showing Up Literally in the Output
Check that the inner token name matches a key available in that context (profile value, or a correctly prefixed config key for that file type). An unresolved inner token, or a typo in the function name, both fall back to leaving the original`[[...]]` text untouched. This does not apply to `env()`, which fails the command instead — see below.My Command Fails With `env() reference(s) could not be resolved`
The error lists every environment variable referenced via `env()` that was either not set, or didn't start with the required prefix (`FLUENT_` by default, or whatever `--env-prefix` was passed). Export the variable with the correct name before re-running, or pass `--env-prefix` if your pipeline uses a different convention.My Command Fails With `env() is only supported when resolving module configuration values`
`env()` was found inside a workflow fragment or asset file, not a module config value. Move the reference into the module config file (e.g. `default:webhook.auth`) and reference the resulting template value from the asset/fragment instead.I Need to Combine Two Transformations
Not supported directly. Resolve the first transformation into a template value in config, then reference that value with a second function call in a different file, since resolved template values are themselves valid function inputs.Best Practices
- Use token functions when the only thing that varies between environments is case, not structure.
- Prefer resolving the transformation once in a module config file (as a named template value) and reusing the plain token elsewhere, rather than repeating the same function call across many files.
- Keep an explicit override in config for any one-off exception rather than special-casing it in a workflow or asset file.
