Terraform Tutorial — Resource Block Anatomy
Every resource block follows the same pattern. Understanding its anatomy lets you read and write any Terraform resource — even ones you’ve never seen before.
The Resource Block
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-unique-bucket-name-2024"
tags = {
Name = "My Bucket"
Environment = "dev"
}
}
Breaking It Down
| Part | Value | Purpose |
|---|---|---|
| Block type | resource |
Tells Terraform this creates infrastructure |
| Resource type | "aws_s3_bucket" |
What kind of resource (provider prefix + resource) |
| Local name | "my_bucket" |
How you reference it in YOUR config |
| Body | { ... } |
Configuration arguments |
Resource Type Format
The resource type is always <provider>_<resource>:
| Resource Type | Provider | Resource |
|---|---|---|
aws_s3_bucket |
AWS | S3 Bucket |
aws_instance |
AWS | EC2 Instance |
aws_vpc |
AWS | Virtual Private Cloud |
azurerm_resource_group |
Azure | Resource Group |
google_compute_instance |
GCP | Compute Instance |
Arguments vs Attributes
Arguments are what you SET (inputs). Attributes are what Terraform RETURNS (outputs).
Arguments (You Write These)
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-unique-bucket-name" # argument: you set this
}
Attributes (Terraform Computes These)
After terraform apply, the resource has attributes you can reference:
# Reference computed attributes
output "bucket_arn" {
value = aws_s3_bucket.my_bucket.arn # computed by AWS
}
output "bucket_domain" {
value = aws_s3_bucket.my_bucket.bucket_regional_domain_name
}
The full reference syntax is: <resource_type>.<local_name>.<attribute>
Required vs Optional Arguments
Every resource has a mix of required and optional arguments:
resource "aws_instance" "web" {
# Required arguments
ami = "ami-0c55b159cbfafe1f0" # Must specify
instance_type = "t3.micro" # Must specify
# Optional arguments
monitoring = true # Default: false
associate_public_ip_address = true # Default: depends on subnet
key_name = "my-key-pair" # Default: none
tags = {
Name = "web-server"
}
}
💡 Tip: Always check the provider documentation to know which arguments are required and which are optional for each resource type.
Resource Addresses
Every resource has a unique address in your configuration:
aws_s3_bucket.my_bucket # Simple resource
aws_instance.web[0] # Resource with count (index 0)
aws_s3_bucket.buckets["logs"] # Resource with for_each (key "logs")
module.vpc.aws_subnet.private[0] # Resource inside a module
You’ll see these addresses in terraform plan output, state commands, and error messages.
What’s Next?
Let’s put this into practice by creating your first real resource — an S3 bucket on AWS.