Skip to content

Resolver functions

You may use resolver functions instead of static values within both config items and decorator values.

Functions can be composed together to create more complex value resolution logic.

ITEM=fn(arg1, arg2)
COMPOSITION=fn1(fn1Arg1, fn2(fn2Arg1, fn2Arg2))

Note that many built-in utility functions have expansion equivalents and often it will be more clear to use them that way. For example:

EXPANSION_EQUIVALENT="pre-${OTHER}-post"
USING_FN_CALLS=concat("pre-", ref(OTHER), "-post")
# mixed example
CONFIG=exec(`aws ssm get-parameter --name "/config/${APP_ENV}" --with-decryption`)

There are built-in utility functions, encryption functions for device-local secrets, and plugin-provided resolver functions that can fetch data from external providers. See the Plugins guide for more information on plugin-provided functions.

References another config item (env var) - which is useful when composing multiple functions together.

Expansion equivalent: ref(OTHER_VARL) === ${OTHER_VAR} (and also $OTHER_VAR)

We recommend using the bracketed version within string templates, and the simpler version when referencing an item directly.

API_URL=https://api.example.com
USERS_API_URL=${API_URL}/users
USERS_API_URL2=concat(ref("API_URL"), "/users") # without using expansion

Concatenates multiple values into a single string.

Expansion uses concat() to combine multiple parts of strings when they include multiple parts.

PATH=concat("base/", ref("APP_ENV"), "/config.json")
PATH2=`base/${APP_ENV}/config.json` # equivalent using expansion

Executes a CLI command and uses its output as the value. This is particularly useful for integrating with external tools and services.

NOTE - many CLI tools output an additional newline. exec() will trim this automatically.

Expansion equivalent: exec(command) === $(command)

# Using 1Password CLI
API_KEY=exec(`op read "op://dev test/service x/api key"`)
# Using AWS CLI
AWS_CREDENTIALS=exec(`aws sts get-session-token --profile prod`)

Returns the first non-empty value in a list of possible values.

POSSIBLY_EMPTY=
ANOTHER=
EXAMPLE=fallback(ref(POSSIBLY_EMPTY), ref(ANOTHER), "default-val")

Maps a value to a new value based on a set of lookup pairs. This is useful for translating one value, often provided by an external platform, into another.

  • The first argument is the value to remap (often a ref() to another variable).
  • All following arguments are pairs of (matchValue, resultValue).
  • An optional trailing default value can be added as the last argument (when the total number of remaining args is odd).
  • Match values can be a string, undefined, or a regex-like string (/pattern/).
  • If no match is found and there is no default, the original value is returned.
# env var that is set by CI/platform
CI_BRANCH=
# @type=enum(development, preview, production)
APP_ENV=remap($CI_BRANCH, "main", production, /.*/, preview, undefined, development)

Evaluates a series of condition/value pairs, returning the value for the first truthy condition. Similar to Excel’s IFS function.

  • Arguments are pairs of (condition, value).
  • An optional trailing default value can be added as the last argument (when the total number of args is odd).
  • If no condition is truthy and there is no default, returns undefined.
ENV=staging
# returns the value matching the first truthy condition
API_URL=ifs(
eq($ENV, production), https://api.example.com,
eq($ENV, staging), https://staging-api.example.com,
http://localhost:3000
)

Certain functions like remap() and type options like matches support regex pattern matching. You can use JavaScript-style regex syntax (/pattern/flags) as an unquoted value — these will be automatically detected and treated as regular expressions.

A string is treated as a regex when it:

  • Starts and ends with / (with optional flags like i, g, m, s, u, y after the closing /)
  • Is not wrapped in quotes
# regex pattern in remap — matches case-insensitively
ENV_TYPE=remap($APP_ENV, /^dev.*/i, dev, "production", prod)
# regex pattern in type options
# @type=string(matches=/^sk-[a-zA-Z0-9]+$/)
API_KEY=
# @type=url(matches=/^https:\/\/api\./)
API_URL=

Resolves to a boolean, if the current environment matches any in the list passed in as args.

Requirements:

  • Requires an @currentEnv to be set in your .env.schema file
  • Takes one or more environment names as arguments
# @currentEnv=$APP_ENV @defaultRequired=false
# @disable=forEnv(test) # entire file will be disabled if env is test
# ---
APP_ENV=staging
# Required only in development
# @required=forEnv(development)
DEV_API_KEY=
# Required in staging and production
# @required=forEnv(staging, production)
PROD_API_KEY=

Checks if 2 values are equal and resolves to a boolean.

IS_STAGING_DEPLOYMENT=eq($GIT_BRANCH, "staging")

Checks a boolean to return a true/false option

API_URL=if(eq($GIT_BRANCH, "main"), api.example.com, staging-api.example.com)

Negates a value and returns a boolean. Falsy values are - false, "", 0, undefined, and will be negated to true. Otherwise will return false.

# Negate the result of another function
SHOULD_DISABLE_FEATURE=not(forEnv(production))

Returns true if the value is undefined or an empty string, false otherwise.

# Check if a value is empty
HAS_API_KEY=not(isEmpty($API_KEY))
# Use with conditional logic
API_URL=if(isEmpty($CUSTOM_API_URL), "https://api.default.com", $CUSTOM_API_URL)

Decrypts a locally encrypted value, or prompts for a new secret to encrypt. This is the built-in resolver for varlock’s device-local encryption feature.

Decrypt mode — pass an encrypted payload to decrypt at load time:

# @sensitive
API_KEY=varlock("local:<encrypted-payload>")

Prompt mode — prompts the user to enter a secret, encrypts it, and writes the encrypted value back to the source file:

# @sensitive
API_KEY=varlock(prompt)
# also valid as a key=value param:
API_KEY=varlock(prompt=1)

On first run with prompt mode, you’ll be asked to enter the secret value. Once entered, the file is automatically updated with the encrypted payload. On macOS with Secure Enclave, a native dialog with biometric authentication is used.

Values are encrypted using the best available backend on your platform — see the Local encryption guide for details.

Encrypted payload lifecycle:

  • Store encrypted payloads (varlock("local:...")) in local override files (typically .env.local)
  • Decryption happens at runtime during varlock load / varlock run
  • Use varlock reveal when you need to inspect a decrypted value interactively

Reads a secret from the macOS Keychain. This built-in resolver communicates through Varlock’s native Swift daemon, enforcing biometric (Touch ID) authentication and per-session access control. See the macOS Keychain page for full documentation.

Array args:

  • service (optional): Service name of the keychain item (positional shorthand)
  • prompt (optional): Enter interactive picker mode

Key/value args:

  • service (optional): Service name of the keychain item
  • account (optional): Account identifier for the keychain item
  • keychain (optional): Name of a specific keychain to search (e.g., "System")
  • field (optional): Specific field to extract from the keychain item
  • prompt (optional): If set, opens a native picker dialog for interactive selection
# Positional shorthand
DATABASE_PASSWORD=keychain("com.company.database")
# Named service with account
ADMIN_PW=keychain("com.company.db", account="admin")
# Interactive picker mode — writes back resolved reference
NEW_SECRET=keychain(prompt)