Terraform Lifecycle Rules Explained - Prevent Accidental Destruction
Master Terraform lifecycle meta-arguments. Covers prevent_destroy, create_before_destroy, ignore_changes, and replace_triggered_by with examples.
Terraform
Understand the difference between Terraform locals and variables. Step-by-step guide with code examples and best practices for Terraform projects.
Terraform locals and variables serve different purposes, but beginners often confuse them. This guide clarifies when to use each with practical examples.
| Feature | Variables | Locals |
|---|---|---|
| Purpose | Accept external input | Compute internal values |
| Set by | User/environment | Configuration code |
| Scope | Module-wide | Module-wide |
| Override | Yes (tfvars, CLI, env) | No |
| Syntax | var.name | local.name |
Variables accept input from outside your module:
variable "environment" {
type = string
default = "dev"
}
variable "instance_count" {
type = number
default = 1
}Set values via:
terraform apply -var="environment=prod"Or in terraform.tfvars:
environment = "prod"
instance_count = 3Locals are computed values used within your configuration:
locals {
name_prefix = "${var.project}-${var.environment}"
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "terraform"
}
is_production = var.environment == "prod"
instance_type = local.is_production ? "t3.large" : "t3.micro"
}Use variables when:
variable "region" {
description = "AWS region"
type = string
}
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}Use locals when:
locals {
# Derived from variables - users shouldn't set these directly
subnet_cidrs = [for i in range(3) : cidrsubnet(var.vpc_cidr, 8, i)]
# Repeated expression - define once, use everywhere
common_tags = merge(var.extra_tags, {
Environment = var.environment
Terraform = "true"
})
# Conditional logic
instance_type = var.environment == "prod" ? "m5.xlarge" : "t3.micro"
}# BAD - this should be a local
variable "name_prefix" {
default = "myapp-dev" # Hardcoded, computed from other values
}
# GOOD
locals {
name_prefix = "${var.app_name}-${var.environment}"
}# BAD - users can't override this
locals {
region = "us-east-1" # Should be configurable
}
# GOOD
variable "region" {
type = string
default = "us-east-1"
}# variables.tf - What users configure
variable "project" { type = string }
variable "environment" { type = string }
variable "instance_count" { type = number; default = 1 }
# locals.tf - What the code computes
locals {
name_prefix = "${var.project}-${var.environment}"
is_production = var.environment == "prod"
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "terraform"
}
}
# main.tf - Uses both
resource "aws_instance" "app" {
count = var.instance_count # User input
instance_type = local.is_production ? "t3.large" : "t3.micro" # Computed
tags = merge(local.common_tags, { Name = "${local.name_prefix}-${count.index}" })
}Variables are for external input; locals are for internal computation. Using each correctly leads to cleaner, more maintainable Terraform code. When in doubt, ask: should the user set this value? If yes, use a variable. If no, use a local.
Master Terraform lifecycle meta-arguments. Covers prevent_destroy, create_before_destroy, ignore_changes, and replace_triggered_by with examples.
Use Terraform dynamic blocks to eliminate repetitive nested blocks. Covers security group rules, IAM policies, and tag generation patterns.
Master conditional expressions in Terraform. Learn ternary operators, conditional resource creation, count and for_each conditionals with examples.
Create and use Terraform modules for reusable infrastructure code. Covers module structure, inputs, outputs, versioning, and the Terraform Registry.