Production-grade Terraform development with HCL best practices, module design, state management, multi-cloud patterns, and AI-enhanced infrastructure as code for scalable cloud deployments
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Production-grade Terraform development with HCL best practices, module design, state management, multi-cloud patterns, and AI-enhanced infrastructure as code for scalable cloud deployments
This skill provides comprehensive guidance for building production-grade infrastructure with Terraform following 2024-2025 best practices. Terraform is the industry standard for Infrastructure as Code (IaC), enabling version-controlled, reproducible, and automated cloud infrastructure management across AWS, Azure, GCP, and 100+ providers.
Automating infrastructure changes with CI/CD pipelines
Creating reusable infrastructure modules for teams
Migrating from manual cloud console provisioning to IaC
Core Principles
1. State Management is Critical
Terraform state is the source of truth - protect it
# CORRECT: Remote state with locking
terraform {
backend "s3" {
bucket = "myapp-terraform-state"
key = "prod/vpc/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-lock" # Prevents concurrent modifications
# State versioning for recovery
versioning = true
}
}
# WRONG: Local state in production
# terraform {
# backend "local" {
# path = "terraform.tfstate" # Never use local state in teams!
# }
# }
State Best Practices:
✅ Always use remote state backends (S3, Azure Blob, GCS, Terraform Cloud)
✅ Enable state locking to prevent concurrent runs
✅ Enable encryption at rest for sensitive data
✅ Use versioning for state file recovery
✅ Separate state files per environment and major component
❌ Never commit .tfstate files to version control
❌ Never share state files via email or Slack
2. Module Design for Reusability
Build composable, tested modules with clear interfaces
# modules/vpc/main.tf - Well-designed module
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
validation {
condition = can(cidrhost(var.vpc_cidr, 0))
error_message = "VPC CIDR must be valid IPv4 CIDR block"
}
}
variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod"
}
}
variable "tags" {
description = "Additional tags for all resources"
type = map(string)
default = {}
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(
{
Name = "${var.environment}-vpc"
Environment = var.environment
ManagedBy = "Terraform"
},
var.tags
)
}
output "vpc_id" {
description = "ID of the created VPC"
value = aws_vpc.main.id
}
output "vpc_cidr" {
description = "CIDR block of the VPC"
value = aws_vpc.main.cidr_block
}
# Usage in root module
module "vpc" {
source = "./modules/vpc"
vpc_cidr = "10.0.0.0/16"
environment = "prod"
tags = {
Team = "platform"
Project = "myapp"
}
}
Module Design Checklist:
✅ Single responsibility - one purpose per module
✅ Input validation with variable validation blocks
✅ Descriptive variable names and descriptions
✅ Sensible defaults where appropriate
✅ Outputs for all important resource attributes
✅ README.md with examples and terraform-docs
✅ Versioning for published modules
3. Resource Naming and Tagging
Consistent naming prevents confusion and enables automation
# WRONG: Hardcoded configuration
resource "aws_instance" "app" {
ami = "ami-12345678" # Will break in other regions!
instance_type = "t3.micro"
tags = {
Environment = "production" # Hardcoded environment
}
}
# CORRECT: Use variables and data sources
data "aws_ami" "app" {
most_recent = true
owners = ["self"]
filter {
name = "name"
values = ["myapp-*"]
}
}
resource "aws_instance" "app" {
ami = data.aws_ami.app.id
instance_type = var.instance_type
tags = merge(local.common_tags, {
Name = "${var.environment}-app"
})
}
❌ DON'T: Use count with lists that may reorder
# WRONG: Count with list - reordering causes recreations
variable "instance_names" {
default = ["web1", "web2", "web3"]
}
resource "aws_instance" "app" {
count = length(var.instance_names)
ami = var.ami_id
instance_type = "t3.micro"
tags = {
Name = var.instance_names[count.index]
}
}
# If you remove "web2", "web3" gets destroyed and recreated!
# CORRECT: Use for_each with map
variable "instances" {
default = {
web1 = { type = "t3.micro" }
web2 = { type = "t3.small" }
web3 = { type = "t3.micro" }
}
}
resource "aws_instance" "app" {
for_each = var.instances
ami = var.ami_id
instance_type = each.value.type
tags = {
Name = each.key
}
}
# Now you can safely add/remove instances without affecting others
❌ DON'T: Mix environments in same state
# WRONG: All environments in one state file
# terraform apply # Applies to dev AND prod!
# CORRECT: Separate directories and state files
# environments/dev/main.tf
# environments/prod/main.tf
❌ DON'T: Use local-exec for critical operations
# WRONG: Critical operations in local-exec
resource "null_resource" "bad_db_init" {
provisioner "local-exec" {
command = "psql -c 'CREATE DATABASE app'"
}
}
# If this fails, no error in Terraform!
# CORRECT: Use proper resources or automation tools
resource "postgresql_database" "app" {
name = "app"
}