terraform-provider-upgrade
Terraform Provider Upgrade Skill
This skill provides a comprehensive workflow for safely upgrading Terraform providers with automatic resource migration, breaking change detection, and proper state management.
When to Use This Skill
- Upgrading provider versions (especially major versions)
- Handling removed or deprecated resources
- Migrating between resource types (e.g.,
azurerm_sql_*→azurerm_mssql_*) - Detecting and resolving breaking changes
- Replacing deprecated provider properties
- Managing Terraform state during upgrades
Determining Breaking vs Non-Breaking Changes
Version Change Analysis
Use MCP tools to understand the scope:
# Get current and latest versions
get_latest_provider_version(namespace="hashicorp", name="azurerm")
# Current: 3.117.0, Latest: 4.51.0 → Major version change (likely breaking)
# Current: 3.117.0, Latest: 3.118.0 → Minor version change (likely non-breaking)
# Current: 3.117.0, Latest: 3.117.1 → Patch version (non-breaking)
# Get upgrade guide to confirm
resolveProviderDocID(...serviceSlug="4.0-upgrade-guide", providerDataType="guides"...)
getProviderDocs(providerDocID="<id>")
Non-Breaking Changes (Auto-Apply)
Characteristics:
- Minor or patch version updates (e.g.,
3.117.0→3.118.0or3.117.1) - No removed resources
- No required argument changes
- Backward-compatible deprecations with drop-in replacements
- New optional arguments or bug fixes
Action:
- Update version constraints in
versions.tf - Apply backward-compatible deprecation replacements if any
- Commit changes without detailed documentation
- Brief commit message:
chore: upgrade azurerm provider to v3.118.0
Breaking Changes (Apply + Document)
Characteristics:
- Major version updates (e.g.,
3.x→4.x) - Removed resources requiring code migration
- Required argument changes (renames, type changes)
- Default value changes affecting behavior
- Authentication or provider configuration changes
Action:
- Apply ALL code changes (resource migrations, moved blocks, argument updates)
- Create comprehensive documentation at repository root:
TERRAFORM_UPGRADE_BREAKING_CHANGES.md - Document what was done (not what needs to be done)
- Detailed commit message referencing documentation
Using MCP Tools to Identify Breaking Changes
Key indicators from upgrade guide:
- Sections titled "Removed Resources", "Breaking Changes", "Behavior Changes"
- Resources listed as "removed" or "superseded by"
- Arguments marked as "renamed", "removed", or "type changed"
- Default value changes that affect existing behavior
Core Workflow
1. Inventory Current State
Objective: Find all provider references and document current versions
# Search for all Terraform files
find . -name "*.tf"
# Search for provider version constraints
grep -r "required_providers" --include="*.tf"
grep -r "version.*=" --include="versions.tf"
Document:
- Current provider versions across all modules/environments
- Location of all provider version constraints
- Environments using the provider
2. Check Latest Versions
Use MCP Tool:
get_latest_provider_version(namespace="hashicorp", name="azurerm")
Compare:
- Current version:
3.117.1 - Latest version:
4.51.0 - Gap: Major version upgrade (3.x → 4.x)
3. Research Breaking Changes
Step 1: Find Upgrade Guide
resolveProviderDocID(
providerNamespace="hashicorp",
providerName="azurerm",
serviceSlug="4.0-upgrade-guide",
providerDataType="guides",
providerVersion="latest"
)
Step 2: Get Documentation
getProviderDocs(providerDocID="<id-from-previous-call>")
Analyze upgrade guide for:
- ✅ Removed resources (resources that no longer exist)
- ✅ Deprecated resources (warnings only)
- ✅ Breaking argument changes (required fields, renamed fields, type changes)
- ✅ New provider features (changes to features {} block)
- ✅ Authentication changes
4. Scan Codebase for Removed Resources
Critical Step: Search for usage of removed resources
# Example: Search for removed SQL resources in Azure v4.0
grep -r "azurerm_sql_server" --include="*.tf"
grep -r "azurerm_sql_firewall_rule" --include="*.tf"
grep -r "azurerm_sql_virtual_network_rule" --include="*.tf"
Document findings:
- Which files use removed resources
- Which environments are affected
- Dependencies between resources
5. Validate Argument Changes
For each removed resource found:
Step 1: Get old resource documentation
resolveProviderDocID(
providerNamespace="hashicorp",
providerName="azurerm",
serviceSlug="sql_server",
providerDataType="resources",
providerVersion="3.117.1"
)
getProviderDocs(providerDocID="<id>")
Step 2: Get new resource documentation
resolveProviderDocID(
providerNamespace="hashicorp",
providerName="azurerm",
serviceSlug="mssql_server",
providerDataType="resources",
providerVersion="latest"
)
getProviderDocs(providerDocID="<id>")
Step 3: Compare schemas
- Required arguments (new required fields?)
- Renamed arguments (e.g.,
administrator_login→admin_login) - Type changes (name → ID references)
- Removed arguments
- New arguments with defaults
Step 4: Check default values
- Document if new resource has different defaults than old resource
- Example: New resource might enable features by default that old resource didn't
6. Apply Code Migrations
Update resource types:
# Before
resource "azurerm_sql_server" "sql_server" {
name = "example-sqlserver"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
version = "12.0"
administrator_login = "sqladmin"
administrator_login_password = var.sql_password
}
# After
resource "azurerm_mssql_server" "sql_server" {
name = "example-sqlserver"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
version = "12.0"
administrator_login = "sqladmin"
administrator_login_password = var.sql_password
}
Add moved block for state migration:
moved {
from = azurerm_sql_server.sql_server
to = azurerm_mssql_server.sql_server
}
Update argument changes:
# Firewall rule arguments changed from name-based to ID-based
# Before (v3.x)
resource "azurerm_sql_firewall_rule" "allow_azure" {
name = "allow-azure-services"
resource_group_name = azurerm_resource_group.rg.name
server_name = azurerm_sql_server.sql_server.name
start_ip_address = "0.0.0.0"
end_ip_address = "0.0.0.0"
}
# After (v4.x)
resource "azurerm_mssql_firewall_rule" "allow_azure" {
name = "allow-azure-services"
server_id = azurerm_mssql_server.sql_server.id # Changed from name to ID
start_ip_address = "0.0.0.0"
end_ip_address = "0.0.0.0"
}
moved {
from = azurerm_sql_firewall_rule.allow_azure
to = azurerm_mssql_firewall_rule.allow_azure
}
Update dependent resources:
# Search for resources that reference the migrated resource
grep -r "azurerm_sql_server.sql_server" --include="*.tf"
Update references to use correct attributes (e.g., .id instead of .name where needed).
Replace deprecated provider properties:
# Before
provider "azurerm" {
features {}
skip_provider_registration = true # Deprecated
}
# After
provider "azurerm" {
features {}
resource_provider_registrations = "none" # Modern equivalent
}
Update version constraints:
terraform {
required_version = ">= 1.5.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "4.51.0" # Updated from 3.117.1
}
}
}
7. Document Changes
Only create documentation for breaking changes.
Create TERRAFORM_UPGRADE_BREAKING_CHANGES.md at repository root (not in .github/ or subdirectories):
File Location:
your-terraform-repo/
├── TERRAFORM_UPGRADE_BREAKING_CHANGES.md ← Place here
├── infra/
├── .github/
└── README.md
# Terraform Provider Upgrade: AzureRM v3.117.1 → v4.51.0
**Date:** 2026-01-27
## Summary
Upgraded HashiCorp AzureRM provider from v3.117.1 to v4.51.0. This major version upgrade included automatic migration of removed SQL resources to their modern MSSQL equivalents.
## What Changed
- Updated `required_providers` version constraint to `4.51.0`
- Migrated removed resources: `azurerm_sql_*` → `azurerm_mssql_*`
- Replaced deprecated `skip_provider_registration` with `resource_provider_registrations`
- Updated argument references from name-based to ID-based
## Breaking Changes Handled
### ✅ Removed Resources Migrated
**1. azurerm_sql_server → azurerm_mssql_server**
- **Files Modified:** `infra/modules/database/main.tf`
- **Changes Applied:**
- Updated resource type
- Added `moved` block for automatic state migration
- All arguments remain compatible
- **Argument Mappings:** No changes required (schema compatible)
- **Default Values:** No new default value changes
- **Documentation:** [azurerm_mssql_server](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_server)
**2. azurerm_sql_firewall_rule → azurerm_mssql_firewall_rule**
- **Files Modified:** `infra/modules/database/main.tf`
- **Changes Applied:**
- Updated resource type
- Changed `server_name` argument to `server_id`
- Updated reference from `.name` to `.id`
- Added `moved` block for automatic state migration
- **Argument Mappings:**
- `resource_group_name` (removed) + `server_name` → `server_id`
- Now uses: `azurerm_mssql_server.sql_server.id`
- **Default Values:** No new default value changes
- **Documentation:** [azurerm_mssql_firewall_rule](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mssql_firewall_rule)
**State Migration:** Terraform will automatically migrate state using `moved` blocks on next plan/apply.
## Notes
- All changes are backward compatible with existing state
- `moved` blocks enable automatic state migration
- No manual `terraform state mv` commands required
- Provider block retained with updated `resource_provider_registrations` argument
## Next Steps
1. **Commit these changes** to a feature branch
2. **Run your Terraform workflow** via CI/CD pipeline to validate
3. **Review plan output** to confirm state migrations
4. **Verify no unexpected changes** before merging
## References
- [AzureRM Provider 4.0 Upgrade Guide](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/4.0-upgrade-guide)
- [AzureRM Provider v4.51.0 Release Notes](https://github.com/hashicorp/terraform-provider-azurerm/releases/tag/v4.51.0)
- [Terraform Moved Blocks](https://developer.hashicorp.com/terraform/language/modules/develop/refactoring)
- [Resource Provider Registrations](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/4.0-upgrade-guide#resource-provider-registrations)
Best Practices
✅ DO:
- Distinguish upgrade types - Check if major (breaking) vs minor/patch (non-breaking)
- Auto-apply non-breaking - Minor/patch updates don't need detailed documentation
- Document breaking only - Create TERRAFORM_UPGRADE_BREAKING_CHANGES.md for major versions
- Place docs at root - Repository root for visibility, not in subdirectories
- Use moved blocks for resource type changes (automatic state migration)
- Validate arguments against official docs for both old and new resources
- Check default values - document if new resource has different defaults
- Update dependent resources that reference migrated resources
- Document what was done - show code changes applied
- Include resource documentation links for transparency
- Use pipeline validation - let CI/CD handle terraform commands
❌ DON'T:
- Document non-breaking changes - Minor/patch versions don't need TERRAFORM_UPGRADE_BREAKING_CHANGES.md
- Provide manual migration steps - code should handle everything
- Assume arguments stayed the same - always validate schemas
- Forget dependent resources - search and update references
- Miss attribute changes - update
.nameto.idwhere needed - Remove provider blocks - only update deprecated arguments
- Suggest terraform commands - users validate via pipeline
Workflow Examples
Example 1: Non-Breaking Upgrade (Minor Version)
Scenario: Upgrading AzureRM from 3.117.0 to 3.118.0
# 1. Check version
get_latest_provider_version(namespace="hashicorp", name="azurerm")
# Result: 3.118.0 (minor version bump)
# 2. Check for breaking changes
resolveProviderDocID(...serviceSlug="3.118.0", providerDataType="guides"...)
getProviderDocs(providerDocID="<id>")
# Review: No removed resources, no breaking changes
# 3. Update version
# versions.tf: version = "3.118.0"
# 4. Commit
# Message: "chore: upgrade azurerm provider to v3.118.0"
# NO TERRAFORM_UPGRADE_BREAKING_CHANGES.md needed
Example 2: Breaking Upgrade (Major Version)
Scenario: Upgrading AzureRM from 3.117.0 to 4.51.0
# 1. Check version
get_latest_provider_version(namespace="hashicorp", name="azurerm")
# Result: 4.51.0 (major version bump)
# 2. Get upgrade guide
resolveProviderDocID(...serviceSlug="4.0-upgrade-guide"...)
getProviderDocs(providerDocID="<id>")
# Review: azurerm_sql_* resources removed
# 3. Scan codebase
grep -r "azurerm_sql_server" --include="*.tf"
# 4. Migrate resources (fetch old + new docs)
# 5. Add moved blocks
# 6. Update arguments
# 7. Create TERRAFORM_UPGRADE_BREAKING_CHANGES.md at repository root
# 8. Commit with detailed message referencing documentation
Best Practices
✅ DO:
- Use moved blocks for resource type changes (automatic state migration)
- Validate arguments against official docs for both old and new resources
- Check default values - document if new resource has different defaults
- Update dependent resources that reference migrated resources
- Document what was done - show code changes applied
- Include resource documentation links for transparency
- Use pipeline validation - let CI/CD handle terraform commands
❌ DON'T:
- Provide manual migration steps - code should handle everything
- Assume arguments stayed the same - always validate schemas
- Forget dependent resources - search and update references
- Miss attribute changes - update
.nameto.idwhere needed - Remove provider blocks - only update deprecated arguments
- Suggest terraform commands - users validate via pipeline
Additional Resources
For detailed examples, common patterns, and troubleshooting, see the reference guide.
More from thomast1906/github-copilot-skills-terraform
azure-verified-modules
Research and learn from Azure Verified Modules (AVM) patterns to build better custom Terraform modules. Use this skill when creating Terraform modules, researching Azure security defaults, understanding proper resource configuration patterns, looking for Microsoft patterns, reference implementation examples, security defaults, or AVM examples. NOT for consuming AVM modules directly.
1terraform-security-scan
Perform security scanning and compliance checking of Terraform configurations for Azure. Use this skill when scanning for security issues, checking CIS/Azure Security Benchmark compliance, auditing Terraform code for vulnerabilities, implementing security gates in CI/CD pipelines, vulnerability scan, security audit, compliance check, CIS benchmark, tfsec, or checkov.
1github-actions-terraform
Debug and fix failing Terraform GitHub Actions workflows. Use this skill when debugging CI/CD failures, fixing Terraform pipeline issues, troubleshooting authentication errors, setting up new GitHub Actions workflows for infrastructure deployments, workflow failed, pipeline error, CI/CD broken, or deploy failure.
1azure-architecture-review
Review Terraform Azure code against Microsoft Cloud Adoption Framework (CAF) and Azure Well-Architected Framework (WAF). Use this skill when reviewing Terraform configurations, validating code against Microsoft frameworks, checking infrastructure-as-code compliance, or performing architecture reviews of .tf files before deployment.
1