DEV Community

Learcise
Learcise

Posted on

Mastering Terraform: From IaC Basics to the Real Difference Between variable and locals

Automating the construction and operation of cloud environments is where Terraform truly shines.

In this article, we’ll organize Terraform’s fundamental concepts and usage, and then dive into one of the most common stumbling blocks: the difference between variable and locals. We’ll explain this in comparison to scoping in JavaScript, with concrete AWS examples so you can easily picture real-world usage.

Why use Terraform?

Traditionally, when building AWS infrastructure manually through the console or CLI, teams often ran into the following issues:

  • Human error: manual operations are prone to mistakes
  • Lack of reproducibility: it’s hard to quickly rebuild the same environment for disaster recovery or new deployments
  • Knowledge silos: build procedures often live only in someone’s head
  • Scaling limitations: managing large-scale environments manually is not feasible
  • Opaque change management: difficult to track who changed what, and when

The solution is Infrastructure as Code (IaC): defining infrastructure in code, enabling reproducibility, automation, and auditability of change history. Terraform is one of the most widely used tools for this.


Key features of Terraform

  • Multi-cloud support: not only AWS, Azure, and GCP, but also Kubernetes, GitHub, and many other providers
  • Declarative syntax: you declare what you want to build, and Terraform resolves dependencies automatically
  • State management: tracks infrastructure state in terraform.tfstate, ensuring differences between code and reality are clear
  • Modularization: encapsulate common setups as modules for reuse

Core building blocks

Here are the main constructs you need to understand Terraform:

Element Role
provider Configures the cloud or service you’ll use (e.g., AWS region, credentials)
resource Defines the infrastructure resources (e.g., EC2, S3, VPC)
data References existing resources
variable Accepts values from outside Terraform
locals Defines reusable values inside the code
module A reusable collection of resources
output Exposes values externally (e.g., an EC2 public IP)

Diving deeper into variable and locals

Key differences

  • variable
    • The entry point for external input
    • Accepts values from CLI flags, environment variables, or tfvars files
    • Used to handle differences between environments (region, env name, instance type, etc.)
  • locals
    • Values for reuse inside the code
    • Cannot be overridden externally
    • Improves readability by centralizing common tags or naming rules

Example in AWS

# variables.tf
variable "region" {
  description = "AWS region"
  type        = string
  default     = "ap-northeast-1"
}

variable "env" {
  description = "Environment name"
  type        = string
  default     = "dev"
}

# locals.tf
locals {
  common_tags = {
    Project     = "sample-app"
    Environment = var.env
  }
}

# s3.tf
provider "aws" {
  region = var.region
}

resource "aws_s3_bucket" "this" {
  bucket = "${var.env}-app-bucket"
  tags   = local.common_tags
}

Enter fullscreen mode Exit fullscreen mode

👉 In this example:

  • region and env can be switched externally
  • common_tags is an internal value reused across resources

Difference from scoping in languages like JavaScript or Python

This is a common point of confusion.

In JavaScript or Python, a variable defined inside a function cannot be referenced outside of it. Terraform’s locals, however, can be referenced across files within the same module (module scope).

Referencing within a module

# locals.tf
locals {
  prefix = "demo"
}

# ec2.tf
resource "aws_instance" "this" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
  tags = {
    Name = "${local.prefix}-server"
  }
}

Enter fullscreen mode Exit fullscreen mode

👉 Even if the files are separate, they belong to the same module, so local.prefix is available everywhere inside that module.

Referencing across modules

However, you cannot reference locals directly from another module.

In such cases, you need to expose values via outputs.

# modules/network/locals.tf
locals {
  vpc_cidr = "10.0.0.0/16"
}

output "vpc_cidr" {
  value = local.vpc_cidr
}

Enter fullscreen mode Exit fullscreen mode
# main.tf
module "network" {
  source = "./modules/network"
}

resource "aws_subnet" "this" {
  cidr_block = module.network.vpc_cidr
}

Enter fullscreen mode Exit fullscreen mode

👉 Remember: locals are module-scoped, not file-scoped.


Essential Terraform commands

Command Description
terraform init Initializes the project and downloads provider plugins
terraform plan Shows a preview of changes before applying
terraform apply Applies the changes and builds infrastructure
terraform destroy Destroys managed resources
terraform fmt Formats the code
terraform validate Validates syntax
terraform output Displays output values
terraform state Inspects and manages the state file

Example project structure (with modules)

.
├── environments
│   ├── dev
│   │   └── main.tf
│   └── prod
│       └── main.tf
└── modules
    └── nginx
        ├── main.tf
        ├── variables.tf
        └── locals.tf

Enter fullscreen mode Exit fullscreen mode
  • environments/dev and environments/prod absorb environment-specific differences
  • modules/nginx encapsulates common logic
  • Use variable for environment-dependent values
  • Use locals to centralize common handling (tags, naming rules)

Best practices

  • Manage state files remotely (e.g., S3 with DynamoDB lock, or Terraform Cloud)
  • Pin provider and Terraform versions
  • Split modules by responsibility for clarity
  • Centralize naming/tagging rules with locals
  • Automate terraform fmt, validate, and plan checks in CI/CD

Conclusion

  • Terraform is a powerful tool for managing infrastructure as code
  • variable is the entry point for external input
  • locals centralizes shared internal values
  • Scoping is module-level: accessible across files within a module, but requires outputs when crossing module boundaries
  • Unlike JavaScript’s function scope, Terraform’s locals follow module scope, which makes reuse across files easier

✅ Would you like me to also make this “polished blog-ready version” with a more natural, engaging tone (like for Medium/Zenn) — or keep it as a straightforward technical translation?

Top comments (0)