Skip to navigation

Variables, locals, and outputs

Variables and external inputs

Declare an input type and optionally a literal default. Omitting the default makes the input required. Root inputs come from a YAML or JSON --vars-file, a data hierarchy, or both; module inputs come from the caller’s arguments. A .json filename selects strict JSON; other names select YAML. No automatic discovery occurs.

variable "message" {
type = string
default = "managed by rivet"
nullable = false
sensitive = false
description = "Text written to the managed file"
}
file "message" {
path = "/etc/rivet-message"
content = "${var.message}\n"
}

To override that default, save this as inputs.yaml:

message: production configuration

The equivalent JSON object is {"message":"production configuration"} in a file ending in .json.

rivet validate ./configuration --vars-file inputs.yaml
rivet compile ./configuration --vars-file inputs.yaml --facts facts.json --out host.bundle
AttributeDefaultRule
typeRequiredScalar, resource handle, or collection type below.
defaultOmittedLiteral typed value; omission requires an input. References/functions are not defaults.
nullabletrueLiteral boolean; false rejects a null input/default.
sensitivefalseLiteral boolean; sensitivity propagates into derived values and collection keys.
descriptionOmittedLiteral string.

The hierarchy resolves low-to-high priority, then --vars-file replaces each supplied variable completely. HCL defaults apply only when no source supplies the variable; they do not fill partial hierarchy objects. Supplied values override defaults. Explicit null follows nullable; it does not fall back to the default. Unknown inputs, duplicate input mapping keys at any depth, wrong types, fractional/out-of-range input numbers, and implicit coercions fail. Input files must be regular YAML/JSON files with string keys and exactly one document. Duplicate keys, custom tags, non-finite numbers, and excessive alias expansion fail. The manifest, layers, decrypted output, and override file share a 16 MiB read budget. Quote numeric-looking strings such as modes ("0644"). Data files cannot fabricate a resource handle.

There is no environment-variable input, automatic variable-file discovery, --var, or variable validation block. Protect input files containing secrets alongside the resulting plaintext bundle. SOPS layers automatically mark supplied variables sensitive; the mark survives later plaintext overrides. validate --explain-inputs reports value-free provenance. See hierarchies and SOPS.

Types

TypeMeaning
string, bool, numberScalars; input and literal numbers are signed 64-bit integers. Numeric facts may be number outputs.
resource("file")A handle of a registered resource type; available for module arguments and outputs.
list(T)Ordered homogeneous elements.
set(T)Deduplicated elements, deterministically sorted; equal values merge provenance/sensitivity.
map(T)String keys with homogeneous values.
object({ name = string, note = optional(string) })Exact named members. Unknown members fail; missing optional members normalize to null.
tuple([string, number])Ordered positions with exact length and positional types.

optional(T) is only an object-member annotation. Collections may contain nested types or resource handles; the bundle reader validates output handles recursively. Lists/tuples preserve order. Top-level nullability is controlled by the variable policy. External inputs reject null collection elements, map values, and required object fields; optional object members may be omitted or null. Partial deep-merge layers normalize optional omissions only after final resolution. Module arguments and outputs and optional resource fields retain their own typed policies.

variable "accounts" {
type = map(object({ home = string, note = optional(string) }))
default = { app = { home = "/var/lib/app" } }
}
variable "names" {
type = set(string)
default = ["app", "ops", "app"]
}
output "account_home" {
type = string
value = var.accounts["app"].home
}
output "names" {
type = set(string)
value = var.names
}

Locals

locals {
message_path = "/etc/rivet-message"
text = "Target ${facts.distribution}"
}
file "summary" {
path = local.message_path
content = local.text
}

Locals are immutable expressions referenced as local.name. They support forward references, collections, handles, and sensitivity and dependency propagation. Duplicate names and cycles fail. Each module has private locals and variables; a child cannot implicitly read the parent.

Outputs

file "config" {
path = "/etc/rivet-config"
content = "enabled\n"
}
output "config_path" {
type = string
value = file.config.path
description = "Where the config is managed"
}
output "config_resource" {
type = resource("file")
value = file.config
}

Outputs require type and value, with optional literal description and sensitivity policies. They are compile-time values, not execution results. A child module’s outputs are its interface, read as module.name.output; only root outputs enter the bundle. Whole-module references cannot be outputs.

There is no rivet output command. graph excludes output values. Sensitive outputs remain confidential plaintext inside the protected bundle; sensitive = false does not clear inherited sensitivity. See modules and expansion.