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.
Use Cases
Section titled “Use Cases”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.
HCL Syntax
Section titled “HCL Syntax”Basic Syntax
Section titled “Basic Syntax”local "name" { value = "computed_value"}
Full Syntax
Section titled “Full Syntax”local "connection_string" { value = resource.database.postgres.meta.name == "postgres" ? "localhost:5432" : resource.database.postgres.connection_string}
Fields
Section titled “Fields”Field | Required | Type | Description |
---|---|---|---|
value | ✓ | any | The computed value expression (can be string, number, boolean, list, or object) |
depends_ | list(string) | List of resource dependencies (inherited from ResourceBase) | |
disabled | bool | Whether this local value is disabled. Defaults to false. |
Local Value Reference
Section titled “Local Value Reference”Local values are referenced in other resources using the syntax:
local.local_name
Examples
Section titled “Examples”Simple Computed Value
Section titled “Simple Computed Value”local "environment_suffix" { value = variable.environment == "production" ? "prod" : "dev"}
resource "container" "web" { image { name = "nginx:latest" }
container_name = "web-${local.environment_suffix}"}
Resource-Based Computation
Section titled “Resource-Based Computation”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 }}
Complex String Building
Section titled “Complex String Building”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 }}
List Manipulation
Section titled “List Manipulation”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 } }}
Object Construction
Section titled “Object Construction”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}
Conditional Resource References
Section titled “Conditional Resource References”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 }}
Multiple Local Dependencies
Section titled “Multiple Local Dependencies”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 }}
Function-Based Computation
Section titled “Function-Based Computation”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" }}
Best Practices
Section titled “Best Practices”- Descriptive Names: Use clear names that describe what the local value represents
- Break Complex Logic: Use locals to make complex expressions more readable
- Avoid Over-Engineering: Don’t create locals for simple values that are used only once
- Group Related Logic: Organize related local values together in your configuration
- Document Purpose: Use meaningful names that make the local value’s purpose obvious
- Consider Dependencies: Be aware that locals can create resource dependencies through their expressions
Common Patterns
Section titled “Common Patterns”Environment-Based Configuration
Section titled “Environment-Based Configuration”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 }}
Dynamic Resource Naming
Section titled “Dynamic Resource Naming”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"}
Configuration Aggregation
Section titled “Configuration Aggregation”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]}
Validation Rules
Section titled “Validation Rules”- 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
Dependencies and Evaluation
Section titled “Dependencies and Evaluation”Local values are processed during the dependency resolution phase:
- Dependency Analysis: The system analyzes the
value
expression to determine dependencies - Evaluation Order: Locals are evaluated after their dependencies are ready
- Type Conversion: Values are automatically converted to appropriate Go types
- 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.