Optimizing Terraform Performance
1. Using Parallelism
Terraform supports parallel execution to speed up operations when managing multiple resources. By default, Terraform runs operations in parallel but with limits to avoid overwhelming the system or external services.
| Setting | Default Value | Description |
|---|---|---|
| max_parallelism | 10 |
Maximum number of concurrent operations (applies to all resources) |
| parallelism | 10 |
Alias for max_parallelism, deprecated in favor of max_parallelism |
Example: Setting Max Parallelism in Configuration
terraform {
required_version = ">= 1.0"
parallelism = 20
}
max_parallelism can lead to resource contention or API throttling if external providers (like AWS, GCP) have rate limits. Monitor system performance and adjust accordingly.
2. Implementing Resource Targeting
Resource targeting allows you to limit Terraform's operations to specific resources or sets of resources, which can significantly improve performance during development and testing.
| Command | Description | Usage Example |
|---|---|---|
| terraform plan -target | Plan only the specified resource(s) | terraform plan -target=aws_instance.web |
| terraform apply -target | Apply only the specified resource(s) | terraform apply -target=aws_s3_bucket.my_bucket |
| terraform destroy -target | Destroy only the specified resource(s) | terraform destroy -target=aws_elasticache_cluster.my_cache |
Example: Targeting Multiple Resources
terraform apply -target=aws_s3_bucket.my_bucket -target=aws_cloudfront_distribution.my_dist
-target can lead to inconsistent states if dependencies are not properly managed. Always ensure that all necessary resources are included in your plan or apply.
3. Disabling Refresh
By default, Terraform performs a refresh operation before executing any plan or apply. This ensures that the state file is up-to-date with the actual infrastructure. However, in some cases, you may want to disable this behavior to improve performance or avoid unintended side effects.
| Option | Values | Description |
|---|---|---|
| -refresh=false | false |
Disables the refresh operation during plan and apply commands. |
4. Splitting Large Configurations
Large Terraform configurations can lead to performance issues and longer execution times. Splitting configurations into smaller, manageable modules improves performance and maintainability.
| Approach | Description | Benefits |
|---|---|---|
| Module-based Splitting | Break configuration into reusable modules using module blocks. |
Improves reusability, readability, and reduces complexity. |
| Backend Configuration | Use remote backends (e.g., remote, s3) to store state efficiently. |
Enables shared state, better collaboration, and performance scaling. |
| Resource Grouping | Group related resources into separate configuration files. | Reduces configuration size and improves deployment speed. |
Example: Module-Based Splitting
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
}
module "ec2_instances" {
source = "./modules/ec2"
vpc_id = module.vpc.vpc_id
}
Best Practices for Splitting Configurations
- Use
moduleblocks to encapsulate logic and resources. - Store state in remote backends for better performance and collaboration.
- Group related resources into separate files to reduce configuration size.
5. Using Remote State Caching
| Option | Values | Notes |
|---|---|---|
| backend | "s3" |
Remote state backend to use for caching |
| bucket | "my-terraform-state" |
S3 bucket name for state storage |
| key | "prod/terraform.tfstate" |
Path to the state file in the bucket |
| region | "us-west-2" |
AWS region for the S3 bucket |
| dynamodb_table | "terraform-locks" |
DynamoDB table for state locking |
Example: Configuring S3 Backend with Caching
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-west-2"
dynamodb_table = "terraform-locks"
}
}
| Feature | Description | Status |
|---|---|---|
| Local State Cache | Stores a local copy of the remote state for faster access | NEW |
| State Locking | Prevents concurrent state modifications with DynamoDB | STABLE |
6. Minimizing Provider API Calls
| Approach | Description | Benefits |
|---|---|---|
| Use data sources efficiently | data "aws_instance" "example" { filter { name = "instance-id" value = "i-1234567890abcdef0" } } |
Reduce API calls by fetching only required data |
| Avoid repeated resource lookups | resource "aws_instance" "example" { ami = data.aws_ami.ubuntu.id } |
Cache results to prevent redundant API queries |
| Batch operations where possible | resource "aws_lb_target_group" "example" { count = 3 name = "tg-${count.index}" } |
Reduce API round trips by grouping resources |
Example: Reducing API Calls with Data Sources
data "aws_ami" "latest" {
most_recent = true
owners = ["123456789012"]
filters {
name = "name"
values = ["ubuntu/images/ubuntu-focal-20.04-amd64-server-*"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.latest.id
instance_type = "t3.micro"
}
data blocks allows Terraform to cache results and avoid repeated API calls during plan/apply phases.
count or for_each on resources that make external API calls without caching.
7. Using Local Caching
| Cache Type | Description | Configuration | Notes |
|---|---|---|---|
| local | Stores state and module downloads locally | backend "local" |
Default behavior for local development |
| remote | Stores state in a remote backend (e.g., S3, GCS) | backend "s3" |
Recommended for team collaboration |
Example: Enabling Local Caching for Modules
terraform {
required_version = "1.9.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.0.0"
}
}
}
provider "aws" {
region = "us-west-2"
}
module "vpc" {
source = "./modules/vpc"
vpc_cidr_block = "10.0.0.0/16"
}
.terraform directory. For performance, ensure this directory is not version-controlled.
terraform init in CI/CD without caching. It can significantly slow down builds.
8. Optimizing Module Structure
| Aspect | Description | Best Practice |
|---|---|---|
| Module Nesting Depth | How deeply modules are nested | Keep nesting under 3 levels to avoid complexity and performance overhead |
| Module Reusability | Ability to reuse modules across different configurations | Design modules with parameters to make them adaptable to various use cases |
| Resource Cohesion | How closely related resources are within a module | Group logically related resources in the same module to reduce inter-module dependencies |
| State Management | How module state is handled and managed | Use local state where possible; avoid excessive remote state dependencies |
Example: Efficient Module Structure
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidr
}
# modules/vpc/variables.tf
variable "vpc_cidr" {
type = string
}
variable "public_subnet_cidr" {
type = string
}
Key Tips for Module Optimization
- Minimize the number of modules to reduce complexity
- Use variables and locals to make modules flexible
- Avoid circular dependencies between modules
- Use
countandfor_eachto handle repetition efficiently
9. Reducing Plan Time
| Strategy | Description | Impact |
|---|---|---|
| Use `terraform plan -target` | Limit planning to specific resources or modules | Significant reduction in plan time for large configurations |
| Avoid `count` and `for_each` in large loops | Use `dynamic` blocks or external data sources instead | Moderate to high reduction in plan time |
| Use `terraform state list` to identify slow resources | Identify and optimize problematic resources | High impact for configurations with many resources |
-target limits the scope of the plan, which can be useful for faster iteration during development.
Best Practices to Reduce Plan Time
- Use
-targetfor focused planning - Avoid unnecessary resource loops
- Use
terraform state listto identify bottlenecks
10. Monitoring Apply Duration
| Metric | Description | Collection Method | Threshold |
|---|---|---|---|
| apply_duration_seconds | Time taken to complete the apply operation in seconds | Using Terraform Cloud/Enterprise metrics or custom logging | Alert if > 300 seconds |
| plan_duration_seconds | Time taken to complete the plan operation in seconds | Same as above | Alert if > 120 seconds |
terraform plan and terraform apply with -json flag to capture detailed timing information for analysis.