What is Infrastructure as Code?
Infrastructure as Code (IaC) is the practice of managing and provisioning infrastructure through machine-readable definition files rather than physical hardware configuration or interactive configuration tools. Terraform implements IaC using a declarative approach where you specify the desired end state, and Terraform determines the actions needed to achieve it.Declarative vs Imperative
Declarative (Terraform)
What you want, not how to achieve it
Imperative (Scripts)
Step-by-step how to create resources
Terraform’s declarative approach means you describe the desired state in configuration files, and Terraform calculates the difference between current and desired state to determine what actions to take.
The Terraform Language (HCL)
Terraform uses HashiCorp Configuration Language (HCL) to define infrastructure. HCL is designed to be both human-readable and machine-parsable.Configuration Structure
Terraform configuration consists of several types of blocks:How Configuration is Processed
The configuration loading process happens ininternal/configs:
Parse HCL Files
The configuration loader reads all
.tf files in a directory and parses them using the HCL parser into an Abstract Syntax Tree (AST).Implementation: configload.LoaderBuild Configuration Model
Terraform constructs a hierarchical model representing the entire configuration, including all modules.Result:
configs.Config objectValidate Structure
Basic structural validation ensures required blocks are present and properly formatted.
Defer Expression Evaluation
Expressions that depend on other resources remain as
hcl.Expression objects for later evaluation during the graph walk.Not all configuration can be interpreted immediately. Values that depend on resource attributes or outputs from other resources are kept as HCL expressions and evaluated during graph execution when dependencies are available.
Resource Declarations
Resources are the most important element in Terraform configuration. Each resource block describes one or more infrastructure objects.Resource Syntax
Resource Addressing
Each resource has a unique address in the format<TYPE>.<NAME>, for example:
aws_instance.web- A single resource instanceaws_instance.web[0]- First instance when usingcountaws_instance.web["prod"]- Instance with key “prod” when usingfor_each
addrs.Resource
Resource Meta-Arguments
Terraform supports several meta-arguments that work with any resource:| Meta-Argument | Purpose | Example |
|---|---|---|
count | Create multiple instances | count = 3 |
for_each | Create instances from a map/set | for_each = var.instances |
depends_on | Explicit dependencies | depends_on = [aws_vpc.main] |
provider | Select provider configuration | provider = aws.west |
lifecycle | Customize resource behavior | See lifecycle section below |
Lifecycle Customization
Thelifecycle block controls how Terraform manages resources:
Expressions and References
Terraform’s expression system enables dynamic configuration through references, functions, and operators.Resource References
Reference attributes of other resources:Expression Evaluation Flow
Expression evaluation happens during vertex execution ininternal/lang:
Analyze References
lang.References analyzes expressions to find which other objects they reference.Build Evaluation Context
Create lookup tables with available values and built-in functions via
lang.Scope.Evaluate Expression
HCL evaluates the expression against the context, producing a
cty.Value.The
cty type system (from github.com/zclconf/go-cty) represents all Terraform values. It supports rich type checking and ensures type safety across the entire system.Modules: Reusable Infrastructure Components
Modules are containers for multiple resources that are used together. Every Terraform configuration has at least one module (the root module).Module Structure
Module Loading
Theconfigload.Loader handles module installation and loading:
- Installation (
terraform init) - Downloads and caches modules from sources - Loading - Recursively loads all child modules to build complete
configs.Config - Expansion - During graph building, modules with
countorfor_eachare dynamically expanded
Variables and Outputs
Input Variables
Input variables parameterize your configuration:eval_variable.go.
Output Values
Outputs expose values for external use:Only root module outputs are persisted in state. Child module outputs exist only during execution to pass values between modules.
Configuration-Driven Behavior
Terraform’s behavior can be customized through configuration rather than command-line flags:Moved Blocks
Document refactoring to prevent destroy/create cycles:Terraform Block
Specify requirements and behavior:Why Configuration as Code Matters
Version Control
Track every infrastructure change in Git with full history and blame information.
Code Review
Review infrastructure changes before applying, catching errors early.
Automation
Integrate with CI/CD pipelines for automated testing and deployment.
Documentation
Configuration serves as living documentation of your infrastructure.
Reusability
Share and reuse modules across projects and teams.
Consistency
Ensure identical infrastructure across environments.
Best Practices
Use Version Control
Use Version Control
Always commit your Terraform configuration to version control. Use
.gitignore to exclude:.terraform/directory*.tfstatefiles (store state remotely instead)*.tfvarsfiles with secrets
Organize with Modules
Organize with Modules
Break large configurations into logical modules. Each module should have a single, well-defined purpose.
Use Variables for Flexibility
Use Variables for Flexibility
Parameterize values that differ between environments or deployments using variables.
Document Your Code
Document Your Code
Use comments and descriptions to explain why decisions were made, not just what the code does.
Next Steps
Execution Plans
Learn how Terraform transforms configuration into actionable plans