Skip to content

Local

The local resource defines computed values that can be reused throughout your lab configuration. Local values are temporary variables that help reduce duplication and make complex expressions more readable by calculating intermediate values that can be referenced by multiple resources.

As a lab author, you can use local values to create more maintainable configurations:

  • Complex Expressions: Break down complex conditional logic into readable intermediate values
  • Resource Name Generation: Compute consistent naming patterns based on variables and other resource attributes
  • Data Transformation: Convert or combine values from multiple sources into formats needed by resources
  • Conditional Logic: Create computed values based on resource states or variable conditions
  • DRY Principle: Eliminate duplication by computing values once and reusing them across multiple resources
  • Dynamic Configuration: Generate configuration values based on runtime conditions or resource attributes

Local values make your configurations more maintainable by centralizing complex logic and reducing code duplication.

local "name" {
value = "computed_value"
}
local "connection_string" {
value = resource.database.postgres.meta.name == "postgres" ? "localhost:5432" : resource.database.postgres.connection_string
}
FieldRequiredTypeDescription
valueanyThe computed value expression (can be string, number, boolean, list, or object)
depends_onlist(string)List of resource dependencies (inherited from ResourceBase)
disabledboolWhether this local value is disabled. Defaults to false.

Local values are referenced in other resources using the syntax:

local.local_name
local "environment_suffix" {
value = variable.environment == "production" ? "prod" : "dev"
}
resource "container" "web" {
image {
name = "nginx:latest"
}
container_name = "web-${local.environment_suffix}"
}
local "database_ready" {
value = resource.container.postgres.meta.name == "postgres" ? "ready" : "pending"
}
resource "container" "app" {
image {
name = "myapp:latest"
}
environment = {
DB_STATUS = local.database_ready
}
}
local "connection_string" {
value = format("postgresql://%s:%s@%s:%d/%s",
variable.db_username,
variable.db_password,
resource.container.postgres.meta.name,
5432,
variable.db_name
)
}
resource "container" "app" {
image {
name = "myapp:latest"
}
environment = {
DATABASE_URL = local.connection_string
}
}
local "service_ports" {
value = [for service in variable.services : service.port]
}
resource "container" "proxy" {
image {
name = "nginx:latest"
}
dynamic "port" {
for_each = local.service_ports
content {
local = port.value
remote = port.value
}
}
}
local "app_config" {
value = {
environment = variable.environment
version = "1.0.0"
features = {
logging = variable.enable_logging
monitoring = variable.enable_monitoring
caching = variable.environment != "development"
}
database = {
host = resource.container.postgres.meta.name
port = 5432
name = variable.db_name
}
}
}
resource "template" "config" {
source = "templates/app.json.tpl"
destination = "./config/app.json"
vars = local.app_config
}
local "storage_path" {
value = variable.use_external_storage ?
resource.volume.external.destination :
"/tmp/data"
}
resource "container" "worker" {
image {
name = "worker:latest"
}
environment = {
DATA_PATH = local.storage_path
}
}
local "base_name" {
value = format("%s-%s", variable.project, variable.environment)
}
local "full_name" {
value = format("%s-%02d", local.base_name, variable.instance_number)
}
resource "container" "app" {
image {
name = "myapp:latest"
}
container_name = local.full_name
environment = {
INSTANCE_NAME = local.full_name
BASE_NAME = local.base_name
}
}
local "service_names" {
value = [for i in range(variable.replica_count) : format("service-%02d", i + 1)]
}
local "primary_service" {
value = element(local.service_names, 0)
}
resource "container" "services" {
count = length(local.service_names)
image {
name = "service:latest"
}
container_name = local.service_names[count.index]
environment = {
IS_PRIMARY = local.service_names[count.index] == local.primary_service ? "true" : "false"
}
}
  1. Descriptive Names: Use clear names that describe what the local value represents
  2. Break Complex Logic: Use locals to make complex expressions more readable
  3. Avoid Over-Engineering: Don’t create locals for simple values that are used only once
  4. Group Related Logic: Organize related local values together in your configuration
  5. Document Purpose: Use meaningful names that make the local value’s purpose obvious
  6. Consider Dependencies: Be aware that locals can create resource dependencies through their expressions
local "is_production" {
value = variable.environment == "production"
}
local "resource_limits" {
value = {
cpu = local.is_production ? 2048 : 1024
memory = local.is_production ? 4096 : 2048
}
}
resource "container" "app" {
image {
name = "myapp:latest"
}
resources {
cpu = local.resource_limits.cpu
memory = local.resource_limits.memory
}
}
local "resource_prefix" {
value = join("-", [variable.project, variable.environment, formatdate("YYYYMMDD", timestamp())])
}
resource "container" "web" {
image {
name = "nginx:latest"
}
container_name = "${local.resource_prefix}-web"
}
resource "container" "api" {
image {
name = "api:latest"
}
container_name = "${local.resource_prefix}-api"
}
local "all_services" {
value = concat(
variable.core_services,
variable.optional_services,
variable.debug_enabled ? ["debugger"] : []
)
}
resource "container" "services" {
count = length(local.all_services)
image {
name = "${local.all_services[count.index]}:latest"
}
container_name = local.all_services[count.index]
}
  • Single Label: Local resources must have exactly one label (the name)
  • Value Expression: The value field should contain a valid HCL expression
  • Circular Dependencies: Local values cannot create circular dependency chains
  • Type Consistency: The computed value type should be consistent with how it’s used

Local values are processed during the dependency resolution phase:

  1. Dependency Analysis: The system analyzes the value expression to determine dependencies
  2. Evaluation Order: Locals are evaluated after their dependencies are ready
  3. Type Conversion: Values are automatically converted to appropriate Go types
  4. Caching: Once computed, local values are cached for subsequent references

Local values help create clean, maintainable configurations by centralizing complex logic and reducing duplication across your lab resources.