/azure-verified-modules
Azure Verified Modules (AVM) requirements and best practices for developing certified Azure Terraform modules. Use when creating or reviewing Azure modules that need AVM certification.
$ npx -y skills add hashicorp/agent-skills --skill azure-verified-modules --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/azure-verified-modules
Context preview
The summary Claude sees to decide when to auto-load this skill.
Azure Verified Modules (AVM) requirements and best practices for developing certified Azure Terraform modules. Use when creating or reviewing Azure modules that need AVM certification.
SKILL.md
azure-verified-modules.SKILL.mdname: azure-verified-modules
description: Azure Verified Modules (AVM) requirements and best practices for developing certified Azure Terraform modules. Use when creating or reviewing Azure modules that need AVM certification.
Azure Verified Modules (AVM) Requirements
This guide covers the mandatory requirements for Azure Verified Modules certification. These requirements ensure consistency, quality, and maintainability across Azure Terraform modules.
**References:**
- [Azure Verified Modules](https://azure.github.io/Azure-Verified-Modules/)
- [AVM Terraform Requirements](https://azure.github.io/Azure-Verified-Modules/specs/terraform/)
Table of Contents
- [Module Cross-Referencing](#module-cross-referencing)
- [Azure Provider Requirements](#azure-provider-requirements)
- [Code Style Standards](#code-style-standards)
- [Variable Requirements](#variable-requirements)
- [Output Requirements](#output-requirements)
- [Local Values Standards](#local-values-standards)
- [Terraform Configuration Requirements](#terraform-configuration-requirements)
- [Testing Requirements](#testing-requirements)
- [Documentation Requirements](#documentation-requirements)
- [Breaking Changes & Feature Management](#breaking-changes--feature-management)
- [Contribution Standards](#contribution-standards)
- [Compliance Checklist](#compliance-checklist)
---
Module Cross-Referencing
**Severity:** MUST | **Requirement:** TFFR1
When building Resource or Pattern modules, module owners **MAY** cross-reference other modules. However:
- Modules **MUST** be referenced using HashiCorp Terraform registry reference to a pinned version
- Example: `source = "Azure/xxx/azurerm"` with `version = "1.2.3"`
- Modules **MUST NOT** use git references (e.g., `git::https://xxx.yyy/xxx.git` or `github.com/xxx/yyy`)
- Modules **MUST NOT** contain references to non-AVM modules
---
Azure Provider Requirements
**Severity:** MUST | **Requirement:** TFFR3
Authors **MUST** only use the following Azure providers:
| Provider | Min Version | Max Version | |----------|-------------|-------------| | azapi | >= 2.0 | < 3.0 | | azurerm | >= 4.0 | < 5.0 |
**Requirements:**
- Authors **MAY** select either Azurerm, Azapi, or both providers
- **MUST** use `required_providers` block to enforce provider versions
- **SHOULD** use pessimistic version constraint operator (`~>`)
**Example:**
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
azapi = {
source = "Azure/azapi"
version = "~> 2.0"
}
}
}---
Code Style Standards
Lower snake_casing
**Severity:** MUST | **Requirement:** TFNFR4
**MUST** use lower snake_casing for:
- Locals
- Variables
- Outputs
- Resources (symbolic names)
- Modules (symbolic names)
Example: `snake_casing_example`
Resource & Data Source Ordering
**Severity:** SHOULD | **Requirement:** TFNFR6
- Resources that are depended on **SHOULD** come first
- Resources with dependencies **SHOULD** be defined close to each other
Count & for_each Usage
**Severity:** MUST | **Requirement:** TFNFR7
- Use `count` for conditional resource creation
- **MUST** use `map(xxx)` or `set(xxx)` as resource's `for_each` collection
- The map's key or set's element **MUST** be static literals
**Example:**
resource "azurerm_subnet" "pair" {
for_each = var.subnet_map # map(string)
name = "${each.value}-pair"
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = ["10.0.1.0/24"]
}Resource & Data Block Internal Ordering
**Severity:** SHOULD | **Requirement:** TFNFR8
**Order within resource/data blocks:**
1. **Meta-arguments (top)**:
- `provider`
- `count`
- `for_each`
2. **Arguments/blocks (middle, alphabetical)**:
- Required arguments
- Optional arguments
- Required nested blocks
- Optional nested blocks
3. **Meta-arguments (bottom)**:
- `depends_on`
- `lifecycle` (with sub-order: `create_before_destroy`, `ignore_changes`, `prevent_destroy`)
Separate sections with blank lines.
Module Block Ordering
**Severity:** SHOULD | **Requirement:** TFNFR9
**Order within module blocks:**
1. **Top meta-arguments**:
- `source`
- `version`
- `count`
- `for_each`
2. **Arguments (alphabetical)**:
- Required arguments
- Optional arguments
3. **Bottom meta-arguments**:
- `depends_on`
- `providers`
Lifecycle ignore_changes Syntax
**Severity:** MUST | **Requirement:** TFNFR10
The `ignore_changes` attribute **MUST NOT** be enclosed in double quotes.
**Good:**
lifecycle {
ignore_changes = [tags]
}**Bad:**
lifecycle {
ignore_changes = ["tags"]
}Null Comparison for Conditional Creation
**Severity:** SHOULD | **Requirement:** TFNFR11
For parameters requiring conditional resource creation, wrap with `object` type to avoid "known after apply" issues during plan stage.
**Recommended:**
variable "security_group" {
type = object({
id = string
})
default = null
}Dynamic Blocks for Optional Nested Objects
**Severity:** MUST | **Requirement:** TFNFR12
Nested blocks under conditions **MUST** use this pattern:
dynamic "identity" {
for_each = <condition> ? [<some_item>] : []
content {
# block content
}
}Default Values with coalesce/try
**Severity:** SHOULD | **Requirement:** TFNFR13
**Good:**
coalesce(var.new_network_security_group_name, "${var.subnet_name}-nsg")**Bad:**
var.new_network_security_group_name == null ? "${var.subnet_name}-nsg" : var.new_network_security_group_nameProvider Declarations in Modules
**Severity:** MUST | **Requirement:** TFNFR27
- `provider` **MUST NOT** be declared in modules (except for `configuration_aliases`)
- `provider` blocks in modules
Read more
name: azure-verified-modules description: Azure Verified Modules (AVM) requirements and best practices for developing certified Azure Terraform modules. Use when creating or reviewing Azure modules that need AVM certification.
Azure Verified Modules (AVM) Requirements
This guide covers the mandatory requirements for Azure Verified Modules certification. These requirements ensure consistency, quality, and maintainability across Azure Terraform modules.
**References:**
- [Azure Verified Modules](https://azure.github.io/Azure-Verified-Modules/)
- [AVM Terraform Requirements](https://azure.github.io/Azure-Verified-Modules/specs/terraform/)
Table of Contents
- [Module Cross-Referencing](#module-cross-referencing)
- [Azure Provider Requirements](#azure-provider-requirements)
- [Code Style Standards](#code-style-standards)
- [Variable Requirements](#variable-requirements)
- [Output Requirements](#output-requirements)
- [Local Values Standards](#local-values-standards)
- [Terraform Configuration Requirements](#terraform-configuration-requirements)
- [Testing Requirements](#testing-requirements)
- [Documentation Requirements](#documentation-requirements)
- [Breaking Changes & Feature Management](#breaking-changes--feature-management)
- [Contribution Standards](#contribution-standards)
- [Compliance Checklist](#compliance-checklist)
---
Module Cross-Referencing
**Severity:** MUST | **Requirement:** TFFR1
When building Resource or Pattern modules, module owners **MAY** cross-reference other modules. However:
- Modules **MUST** be referenced using HashiCorp Terraform registry reference to a pinned version
- Example: `source = "Azure/xxx/azurerm"` with `version = "1.2.3"`
- Modules **MUST NOT** use git references (e.g., `git::https://xxx.yyy/xxx.git` or `github.com/xxx/yyy`)
- Modules **MUST NOT** contain references to non-AVM modules
---
Azure Provider Requirements
**Severity:** MUST | **Requirement:** TFFR3
Authors **MUST** only use the following Azure providers:
| Provider | Min Version | Max Version | |----------|-------------|-------------| | azapi | >= 2.0 | < 3.0 | | azurerm | >= 4.0 | < 5.0 |
**Requirements:**
- Authors **MAY** select either Azurerm, Azapi, or both providers
- **MUST** use `required_providers` block to enforce provider versions
- **SHOULD** use pessimistic version constraint operator (`~>`)
**Example:**
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
azapi = {
source = "Azure/azapi"
version = "~> 2.0"
}
}
}---
Code Style Standards
Lower snake_casing
**Severity:** MUST | **Requirement:** TFNFR4
**MUST** use lower snake_casing for:
- Locals
- Variables
- Outputs
- Resources (symbolic names)
- Modules (symbolic names)
Example: `snake_casing_example`
Resource & Data Source Ordering
**Severity:** SHOULD | **Requirement:** TFNFR6
- Resources that are depended on **SHOULD** come first
- Resources with dependencies **SHOULD** be defined close to each other
Count & for_each Usage
**Severity:** MUST | **Requirement:** TFNFR7
- Use `count` for conditional resource creation
- **MUST** use `map(xxx)` or `set(xxx)` as resource's `for_each` collection
- The map's key or set's element **MUST** be static literals
**Example:**
resource "azurerm_subnet" "pair" {
for_each = var.subnet_map # map(string)
name = "${each.value}-pair"
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefixes = ["10.0.1.0/24"]
}Resource & Data Block Internal Ordering
**Severity:** SHOULD | **Requirement:** TFNFR8
**Order within resource/data blocks:**
1. **Meta-arguments (top)**:
- `provider`
- `count`
- `for_each`
2. **Arguments/blocks (middle, alphabetical)**:
- Required arguments
- Optional arguments
- Required nested blocks
- Optional nested blocks
3. **Meta-arguments (bottom)**:
- `depends_on`
- `lifecycle` (with sub-order: `create_before_destroy`, `ignore_changes`, `prevent_destroy`)
Separate sections with blank lines.
Module Block Ordering
**Severity:** SHOULD | **Requirement:** TFNFR9
**Order within module blocks:**
1. **Top meta-arguments**:
- `source`
- `version`
- `count`
- `for_each`
2. **Arguments (alphabetical)**:
- Required arguments
- Optional arguments
3. **Bottom meta-arguments**:
- `depends_on`
- `providers`
Lifecycle ignore_changes Syntax
**Severity:** MUST | **Requirement:** TFNFR10
The `ignore_changes` attribute **MUST NOT** be enclosed in double quotes.
**Good:**
lifecycle {
ignore_changes = [tags]
}**Bad:**
lifecycle {
ignore_changes = ["tags"]
}Null Comparison for Conditional Creation
**Severity:** SHOULD | **Requirement:** TFNFR11
For parameters requiring conditional resource creation, wrap with `object` type to avoid "known after apply" issues during plan stage.
**Recommended:**
variable "security_group" {
type = object({
id = string
})
default = null
}Dynamic Blocks for Optional Nested Objects
**Severity:** MUST | **Requirement:** TFNFR12
Nested blocks under conditions **MUST** use this pattern:
dynamic "identity" {
for_each = <condition> ? [<some_item>] : []
content {
# block content
}
}Default Values with coalesce/try
**Severity:** SHOULD | **Requirement:** TFNFR13
**Good:**
coalesce(var.new_network_security_group_name, "${var.subnet_name}-nsg")**Bad:**
var.new_network_security_group_name == null ? "${var.subnet_name}-nsg" : var.new_network_security_group_nameProvider Declarations in Modules
**Severity:** MUST | **Requirement:** TFNFR27
- `provider` **MUST NOT** be declared in modules (except for `configuration_aliases`)
- `provider` blocks in modules
A collection of Agent skills and Claude Code plugins for HashiCorp products. Legal Note: Your use of a third party MCP Client/LLM is subject solely to the terms of use for such MCP/LLM, and IBM is not responsible for the performance of such third party tools.
Repo: hashicorp/agent-skills
Other skills on hashicorp-agent-skills.
- /aws-ami-builder
Build Amazon Machine Images (AMIs) with Packer using the amazon-ebs builder. Use when creating custom AMIs for EC2 instances.
Open skill - /azure-image-builder
Build Azure managed images and Azure Compute Gallery images with Packer. Use when creating custom images for Azure VMs.
Open skill - /windows-builder
Build Windows images with Packer using WinRM communicator and PowerShell provisioners. Use when creating Windows AMIs, Azure images, or VMware templates.
Open skill - /push-to-registry
Push Packer build metadata to HCP Packer registry for tracking and managing image lifecycle. Use when integrating Packer builds with HCP Packer for version control and governance.
Open skill - /terraform-search-import
Discover existing cloud resources using Terraform Search queries and bulk import them into Terraform management. Use when bringing unmanaged infrastructure under Terraform control, auditing cloud resources, or migrating to IaC.
Open skill - /terraform-style-guide
Generate Terraform HCL code following HashiCorp's official style conventions and best practices. Use when writing, reviewing, or generating Terraform configurations.
Open skill

