{"name":"terraform-style-guide","url":"https://skills.sh/hashicorp/terraform-agent-kit/terraform-style-guide","install":"npx skills add hashicorp/terraform-agent-kit --skill terraform-style-guide","sdk":"terraform","key":"terraform/terraform-style-guide","description":"Generate Terraform HCL code following HashiCorp's official style conventions and best practices. Use when writing, reviewing, or generating Terraform configurations.","hasContent":true,"content":"---\nname: terraform-style-guide\ndescription: Generate Terraform HCL code following HashiCorp's official style conventions and best practices. Use when writing, reviewing, or generating Terraform configurations.\n---\n\n# Terraform Style Guide\n\nGenerate and maintain Terraform code following HashiCorp's official style conventions and best practices.\n\n**Reference:** [HashiCorp Terraform Style Guide](https://developer.hashicorp.com/terraform/language/style)\n\n## Code Generation Strategy\n\nWhen generating Terraform code:\n\n1. Start with provider configuration and version constraints\n2. Create data sources before dependent resources\n3. Build resources in dependency order\n4. Add outputs for key resource attributes\n5. Use variables for all configurable values\n\n## File Organization\n\n| File | Purpose |\n|------|---------|\n| `terraform.tf` | Terraform and provider version requirements |\n| `providers.tf` | Provider configurations |\n| `main.tf` | Primary resources and data sources |\n| `variables.tf` | Input variable declarations (alphabetical) |\n| `outputs.tf` | Output value declarations (alphabetical) |\n| `locals.tf` | Local value declarations |\n\n### Example Structure\n\n```hcl\n# terraform.tf\nterraform {\n  required_version = \">= 1.14\"\n\n  required_providers {\n    aws = {\n      source  = \"hashicorp/aws\"\n      version = \"~> 6.0\"\n    }\n  }\n}\n\n# variables.tf\nvariable \"environment\" {\n  description = \"Target deployment environment\"\n  type        = string\n\n  validation {\n    condition     = contains([\"dev\", \"staging\", \"prod\"], var.environment)\n    error_message = \"Environment must be dev, staging, or prod.\"\n  }\n}\n\n# locals.tf\nlocals {\n  common_tags = {\n    Environment = var.environment\n    ManagedBy   = \"Terraform\"\n  }\n}\n\n# main.tf\nresource \"aws_vpc\" \"main\" {\n  cidr_block           = var.vpc_cidr\n  enable_dns_hostnames = true\n\n  tags = merge(local.common_tags, {\n    Name = \"${var.project_name}-${var.environment}-vpc\"\n  })\n}\n\n# outputs.tf\noutput \"vpc_id\" {\n  description = \"ID of the created VPC\"\n  value       = aws_vpc.main.id\n}\n```\n\n## Code Formatting\n\n### Indentation and Alignment\n\n- Use **two spaces** per nesting level (no tabs)\n- Align equals signs for consecutive arguments\n\n```hcl\nresource \"aws_instance\" \"web\" {\n  ami           = \"ami-0c55b159cbfafe1f0\"\n  instance_type = \"t2.micro\"\n  subnet_id     = \"subnet-12345678\"\n\n  tags = {\n    Name        = \"web-server\"\n    Environment = \"production\"\n  }\n}\n```\n\n### Block Organization\n\nArguments precede blocks, with meta-arguments first:\n\n```hcl\nresource \"aws_instance\" \"example\" {\n  # Meta-arguments\n  count = 3\n\n  # Arguments\n  ami           = \"ami-0c55b159cbfafe1f0\"\n  instance_type = \"t2.micro\"\n\n  # Blocks\n  root_block_device {\n    volume_size = 20\n  }\n\n  # Lifecycle last\n  lifecycle {\n    create_before_destroy = true\n  }\n}\n```\n\n## Naming Conventions\n\n- Use **lowercase with underscores** for all names\n- Use **descriptive nouns** excluding the resource type\n- Be specific and meaningful\n- Resource names must be singular, not plural\n- Default to `main` for resources where a specific descriptive name is redundant or unavailable, provided only one instance exists\n\n```hcl\n# Bad\nresource \"aws_instance\" \"webAPI-aws-instance\" {}\nresource \"aws_instance\" \"web_apis\" {}\nvariable \"name\" {}\n\n# Good\nresource \"aws_instance\" \"web_api\" {}\nresource \"aws_vpc\" \"main\" {}\nvariable \"application_name\" {}\n```\n\n## Variables\n\nEvery variable must include `type` and `description`:\n\n```hcl\nvariable \"instance_type\" {\n  description = \"EC2 instance type for the web server\"\n  type        = string\n  default     = \"t2.micro\"\n\n  validation {\n    condition     = contains([\"t2.micro\", \"t2.small\", \"t2.medium\"], var.instance_type)\n    error_message = \"Instance type must be t2.micro, t2.small, or t2.medium.\"\n  }\n}\n\nvariable \"database_password\" {\n  description = \"Password for the database admin user\"\n  type        = string\n  sensitive   = true\n}\n```\n\n## Outputs\n\nEvery output must include `description`:\n\n```hcl\noutput \"instance_id\" {\n  description = \"ID of the EC2 instance\"\n  value       = aws_instance.web.id\n}\n\noutput \"database_password\" {\n  description = \"Database administrator password\"\n  value       = aws_db_instance.main.password\n  sensitive   = true\n}\n```\n\n## Dynamic Resource Creation\n\n### Prefer for_each over count\n\n```hcl\n# Bad - count for multiple resources\nresource \"aws_instance\" \"web\" {\n  count = var.instance_count\n  tags  = { Name = \"web-${count.index}\" }\n}\n\n# Good - for_each with named instances\nvariable \"instance_names\" {\n  type    = set(string)\n  default = [\"web-1\", \"web-2\", \"web-3\"]\n}\n\nresource \"aws_instance\" \"web\" {\n  for_each = var.instance_names\n  tags     = { Name = each.key }\n}\n```\n\n### count for Conditional Creation\n\n```hcl\nresource \"aws_cloudwatch_metric_alarm\" \"cpu\" {\n  count = var.enable_monitoring ? 1 : 0\n\n  alarm_name = \"high-cpu-usage\"\n  threshold  = 80\n}\n```\n\n## Security Best Practices\n\nRefer to SECURITY.md. It includes guidance on encrypting resources,\npreventing sensitive data in state, and secure configurations.\n\n## Version Pinning\n\n```hcl\nterraform {\n  required_version = \">= 1.14\"\n\n  required_providers {\n    aws = {\n      source  = \"hashicorp/aws\"\n      version = \"~> 6.0\"\n    }\n  }\n}\n```\n\nUse the latest major version of each provider and the latest minor version of\nTerraform, unless otherwise constrained by a dependency lock file or by other\nmodules used by the configuration.\n\n**Version constraint operators:**\n- `= 1.0.0` - Exact version\n- `>= 1.0.0` - Greater than or equal\n- `~> 1.0` - Allow rightmost component to increment\n- `>= 1.0, < 2.0` - Version range\n\n## Provider Configuration\n\n```hcl\nprovider \"aws\" {\n  region = \"us-west-2\"\n\n  default_tags {\n    tags = {\n      ManagedBy = \"Terraform\"\n      Project   = var.project_name\n    }\n  }\n}\n\n# Aliased provider for multi-region\nprovider \"aws\" {\n  alias  = \"east\"\n  region = \"us-east-1\"\n}\n```\n\n## Version Control\n\n**Never commit:**\n- `terraform.tfstate`, `terraform.tfstate.backup`\n- `.terraform/` directory\n- `*.tfplan`\n- `.tfvars` files with sensitive data\n\n**Always commit:**\n- All `.tf` configuration files\n- `.terraform.lock.hcl` (dependency lock file)\n\n## Validation Tools\n\nRun before committing:\n\n```bash\nterraform fmt -recursive\nterraform validate\n```\n\nAdditional tools:\n- `tflint` - Linting and best practices\n- `checkov` / `tfsec` - Security scanning\n\n## Code Review Checklist\n\n- [ ] Code formatted with `terraform fmt`\n- [ ] Configuration validated with `terraform validate`\n- [ ] Files organized according to standard structure\n- [ ] All variables have type and description\n- [ ] All outputs have descriptions\n- [ ] Resource names use descriptive nouns with underscores\n- [ ] Version constraints pinned explicitly\n- [ ] Sensitive values marked with `sensitive = true`\n- [ ] No hardcoded credentials or secrets\n- [ ] Security best practices applied\n\n---\n\n*Based on: [HashiCorp Terraform Style Guide](https://developer.hashicorp.com/terraform/language/style)*\n","contentSource":"skills.sh/api/download/hashicorp/terraform-agent-kit/terraform-style-guide","contentFetchedAt":"2026-07-27T08:59:33.848Z"}