Expression reference#

Orchard uses HCL expressions with a cty type system. This page covers the reference namespaces, type expressions, and available functions.

Reference namespaces#

Five reference namespaces are available inside expressions:

FormScopeAvailable when
var.<name>Scenario (or component) variables.Immediately — resolved up front.
action.<type>.<name>.<output>Action outputs.After the referenced action completes.
component.<type>.<name>.<output>Component instance outputs.After the component resolves.
var.<name> (inside a component)The component’s own variables.Immediately, scoped to the component.
self.<output>The current action’s own outputs.Inside lifecycle { teardown { } } blocks only.

Variable references#

provider "postgres" {
  dsn = var.dsn
}

action "postgres_query" "insert" {
  query = "INSERT INTO t (name) VALUES ('${var.name}')"
}

Variable references are resolved at plan time. They cannot participate in the dependency graph — if you need ordering, reference an action or component output instead.

Action references#

action "postgres_query" "next" {
  query = "SELECT * FROM users WHERE id = ${action.postgres_query.previous.user_id}"
}

output "merchant_id" {
  value = action.postgres_query.create_merchant.id
}

action.<type>.<name>.<output> — all three segments are required. The <output> segment depends on what the provider’s action schema declares.

Component references#

action "postgres_query" "attach" {
  query = "INSERT ... VALUES (${component.merchant.acme.id})"
}

component.<type>.<name>.<output> — where <type> matches the component’s declared name in its source file and <name> matches the instance label in the scenario.

self (teardown only)#

Inside a lifecycle { teardown { } } block, self.<field> refers to the action’s own recorded outputs. This lets authors write teardowns without repeating the node name:

action "postgres_query" "create_merchant" {
  query = "INSERT INTO merchants (name) VALUES ('${var.name}') RETURNING id"

  lifecycle {
    teardown {
      query = "DELETE FROM merchants WHERE id = ${self.id}"
    }
  }
}

self is only populated when orchard teardown <record> evaluates the body; the values come from the record’s per-node outputs captured at run time. Inside the action’s main body (during orchard run), self is not in scope.

Type expressions#

Types are written as cty type expressions:

ExpressionMeaning
stringString.
numberNumber (integer or float).
boolBoolean.
list(T)List of T.
set(T)Set of T.
map(T)Map from string to T.
object({ k = T, ... })Object with fixed keys.
tuple([T1, T2, ...])Tuple with positional types.
anyAny cty value (dynamic type).

Examples:

variable "count" {
  type    = number
  default = 1
}

variable "tags" {
  type    = list(string)
  default = ["demo", "dev"]
}

variable "config" {
  type = object({
    retries = number
    timeout = string
  })
}

Omitting type is equivalent to declaring type = any.

String interpolation#

HCL supports ${ ... } interpolation inside strings:

query = "INSERT INTO merchants (name) VALUES ('${var.name}')"

Quote carefully when interpolating into SQL, shell commands, or HTTP URLs — Orchard does not escape values for you.

Operators#

Standard HCL operators are available:

  • Arithmetic: +, -, *, /, %
  • Comparison: ==, !=, <, <=, >, >=
  • Logical: &&, ||, !
  • Conditional: cond ? a : b
variable "environment" { default = "dev" }

action "postgres_query" "seed" {
  query = var.environment == "prod" ? "SELECT 1" : "INSERT INTO ..."
}

Functions#

See the functions reference for the complete list of all available functions with signatures, descriptions, parameter tables, and examples. The reference is auto-generated from Orchard’s function registry so it stays in sync with the binary.

Reference syntax in depends_on#

depends_on accepts references as bare traversals — not strings:

action "postgres_query" "b" {
  depends_on = [action.postgres_query.a, component.merchant.acme]
  query      = "..."
}

These references don’t pull any data into scope; they only create graph edges.