Overview
Nomad Variables are a convenient way to store configuration data, but they cannot be used inside dynamic blocks. This article demonstrates both the failure case (with real errors) and the working alternative using template stanzas.
Pre-requisites
- Docker installed and running. Refer this.
- Nomad installed and running. Refer this.
- Consul installed and running. Refer this.
1. Non‑Working Setup: Dynamic Blocks with Variables
variable "my_structured_var" {
type = map(string)
default = {
app1 = "value1"
app2 = "value2"
}
}
job "example" {
datacenters = ["dc1"]
group "app" {
dynamic "task" {
for_each = var.my_structured_var
labels = {
name = task.key
value = task.value
}
content {
driver = "docker"
config {
image = "busybox:latest"
command = "echo"
args = ["${task.key}=${task.value}"]
}
}
}
}
}Error Received
When running:
nomad job run example.nomad
Nomad fails with:
Error parsing job file from example.nomad: example.nomad:16,16-17: Invalid expression; A static list expression is required.
Why This Happens
- Dynamic blocks in Nomad require static lists/maps at parse time.
- Nomad Variables are resolved later at runtime, so they cannot be used in
for_each. - This is the expected error and confirms the limitation.
2. Working Setup: Template Stanza with Consul KV
Instead of dynamic blocks, use a template stanza. Templates are evaluated at runtime, so they can access Nomad Variables or Consul KV data.
job "tetris" {
datacenters = ["dc1"]
group "games" {
count = 3
network {
port "web" {
to = 80
}
}
task "tetris" {
driver = "docker"
config {
image = "bsord/tetris"
ports = ["web"]
}
resources {
cpu = 50
memory = 256
}
template {
data = <<EOH
{{ with key "app/config" | parseJSON }}
Feature flag: {{ .feature_flag }}
API URL: {{ .api_url }}
{{ end }}
EOH
destination = "local/config.json"
}
}
}
}Setup
-
Store config in Consul KV:
consul kv put app/config '{"feature_flag": true, "api_url": "https://example.com"}' -
Run the job:
nomad job run tetris.nomad.hcl
-
Inspect the rendered file:
nomad alloc exec <alloc_id> cat local/config.json
Expected Output
Feature flag: true API URL: https://example.com
3. Recommended Pattern: Consul KV for Shared Config
For structured configuration shared across jobs, use Consul KV:
- Better suited for larger data.
- Supports ACLs and scoping.
- Works seamlessly with template stanzas.
4. References
https://developer.hashicorp.com/nomad/docs/concepts/variables
https://developer.hashicorp.com/consul/docs/automate/kv