> ## Documentation Index
> Fetch the complete documentation index at: https://yukta.infenia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Variables and expressions

> Reference message data, settings and secrets inside node configuration without storing them in the workflow.

Any string in a node's `config` can contain a **placeholder** written `${...}`. The server resolves placeholders just before the node runs, from message data, an allow-list of settings, or a secret store. This keeps secrets out of stored workflow definitions and lets one definition adapt to its input.

<Note>
  The placeholder syntax is pre-beta and may change before v0.1.0.
</Note>

## Sources

| Placeholder | Resolves to |
| - | - |
| `${payload}` | The whole payload of the message being processed |
| `${payload.a.b}` | A nested field of the payload (maps only, dot-separated) |
| `${metadata.key}` | A label on the message, for example `${metadata.signal.decision}` |
| `${env.NAME}` | An environment variable of the server, if allowed (see below) |
| `${sys.name}` | A system setting of the server, if allowed (see below) |
| `decrypted:name` | A secret, looked up by name. Write the whole value as `decrypted:name` |

A placeholder that cannot be resolved against the message returns an empty value. If a node's configuration cannot be resolved at all, that message fails like any other plugin failure, so [retries and error routing](/concepts/failure-handling) apply.

```json theme={"system"}
{
  "nodeId": "notify",
  "type": "HTTP_REQUEST",
  "config": {
    "url": "https://chat.example.com/hooks/ops",
    "method": "POST",
    "headers": { "Authorization": "decrypted:chat-token" },
    "body": { "text": "Build ${payload.build} finished with ${payload.status}" }
  }
}
```

The option names depend on the plugin; see [External I/O](/plugins/external-io).

## Interpolation and types

* When a value is exactly one placeholder, such as `"${payload.count}"`, the **type is preserved**: a number stays a number.
* When a placeholder is part of a longer string, such as `"Build ${payload.build}"`, the result is text.
* To force a type, add a suffix: `${payload.secs:int}`. Supported suffixes are `int` (or `integer`), `long`, `double` (or `float`), `bool` (or `boolean`) and `string`.

Write numeric options as typed placeholders so the server can read them. An option whose value is unknown until a message arrives, such as a timeout, is re-timed when the first message comes in; see [Time limits](/concepts/time-limits).

## Environment and system values

Workflows can read only a short list of server values, because a server holds more than secrets:

| Readable | Examples |
| - | - |
| Names with the prefix `YUKTA_VAR_` (environment) or `yukta.var.` (settings) | `${env.YUKTA_VAR_REGION}`, `${sys.yukta.var.region}` |
| A short list of harmless names | `HOME`, `USER`, `LANG`, `TZ`, `HOSTNAME`, `PWD`, `PATH`, `user.name`, `user.home`, `user.dir`, `user.timezone`, `os.name`, `file.separator`, `path.separator`, `line.separator` |
| Names you list in `yukta.variables.allowed` or `YUKTA_VARIABLES_ALLOWED` | comma-separated |

Names that look like secrets (containing `PASSWORD`, `PASSWD`, `SECRET`, `TOKEN`, `CREDENTIAL`, `PRIVATE` or `KEY`) stay blocked even if you list them. Use the secret store for those. Reading a name that is not allowed fails the message with a clear error.

## Secrets

Write a secret as `decrypted:name`. The default secret provider reads the environment variable `YUKTA_SECRET_<NAME>` (the name is upper-cased), so secret values never appear in a stored definition, in versions or in logs of the definition.

```properties theme={"system"}
# environment of the server
YUKTA_SECRET_CHAT_TOKEN=xoxb-example
```

A secret that is not found fails the message.

## Expressions

Several plugins take an **expression** instead of a plain value: branch cases, filter predicates, mapper projections and loop exit conditions. Expressions read the message through `payload` and `metadata`:

```text theme={"system"}
payload.coverage >= 80 && payload.lintErrors == 0
```

Expressions can call only a short list of safe methods. Scripts in the mapper plugin run with a time limit and a statement limit. See [Transform](/plugins/transform) and [Routing and flow control](/plugins/routing-and-flow) for the syntax each node accepts, and [Security](/operations/security) for the limits.

## Related

* [Security](/operations/security)
* [Configuration](/operations/configuration)
* [Routing and branching](/building/routing-and-branching)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.