---
title: How to Upgrade the AWS Terraform Provider Safely: Strategy, Testing, and Rollback
description: AWS provider 6.0 GA June 2025. July 2026: upgrade 4 to 5 to 6 one major at a time, changelog-first, staging plan, lockfile commit.
url: https://www.joinhorizon.co/blog/terraform-aws-provider-upgrade-strategy/
datePublished: 2026-04-04T00:00:00.000Z
dateModified: 2026-10-28T00:00:00.000Z
author: manojkumar-varatharajan
category: DevOps & CI/CD
tags: terraform, aws-provider, version-management, devops, infrastructure-modernization
---

# How to Upgrade the AWS Terraform Provider Safely: Strategy, Testing, and Rollback

> AWS provider 6.0 GA June 2025. July 2026: upgrade 4 to 5 to 6 one major at a time, changelog-first, staging plan, lockfile commit.

Your Terraform configuration still says `required_providers { aws = "~> 4.0" }` (or a soft `~> 5.0` while **hashicorp/aws 6.x** has been GA since **18 June 2025**). As of **July 2026**, that gap is not cosmetic: you miss resources and defaults, and on the 5 to 6 jump you miss **enhanced per-resource `region`** support, which changes how multi-region stacks are written.

**First-party benchmark (illustrative):** a mid-size SaaS with ~180 AWS resources and a 4.x pin often needs a dedicated staging PR per major (4 to 5, then 5 to 6). Skipping majors in one apply is how “zero plan changes” turns into surprise replaces.

**Reproduce this:** [AWS provider major-upgrade checklist](https://www.joinhorizon.co/examples/architecture-blog-2026/terraform-provider-upgrade/aws-provider-major-upgrade-checklist.md)

**Counter-case:** do **not** treat `terraform init -upgrade` in production as the upgrade strategy. Do the changelog and a staging plan first.

This guide covers the audit, changelog triage, one-major-at-a-time testing, the lockfile commit, and a controlled prod apply.

## Why provider versions fall behind

Most teams don't intentionally stay on old provider versions. It happens passively:

1. **You set up Terraform two years ago** with version `"~> 4.0"`
2. **That version works fine** and you don't think about it
3. **New resources are released**, but they only work with newer provider versions
4. **You try to use a new resource** and get "resource not found" errors
5. **Security vulnerability** is discovered in an old provider, but you don't know about it

The AWS provider releases new versions constantly:

- **Major versions** introduce breaking changes (4.0 to 5.0)
- **Minor versions** introduce new resources and features (4.50 to 4.51)
- **Patch versions** fix bugs and security issues (4.50.0 to 4.50.1)

Most teams stay 1 to 2 minor versions behind, but many are 2 to 3 **major** versions behind, which means significant breaking changes.

## Step 1: Audit your current provider version

Start by understanding what you're running.

### Check your lock file

The most authoritative source is your `.terraform.lock.hcl` file:

```hcl
provider "registry.terraform.io/hashicorp/aws" {
  version     = "5.12.0"
  constraints = "~> 5.0"
  hashes = [
    "h1:...",
  ]
}
```

This tells you: you're currently running version 5.12.0, and your constraint allows 5.x.x (but not 6.x.x).

### Check your configuration

Look at your root `terraform.tf`:

```hcl
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.50"
    }
  }
}
```

The version constraint `~> 4.50` means: allow 4.50.x and 4.51.x and 4.52.x, but not 5.0.0 (breaking changes).

### Check AWS provider releases

Visit [releases.hashicorp.com](https://releases.hashicorp.com/terraform-provider-aws/) to see:

- Current latest version
- Release history
- Breaking changes per version

**Current state (as of July 2026):**

- Latest stable line: **6.x** (6.0 GA **2025-06-18**; enhanced Region support via top-level `region` on most resources)
- Previous major: **5.x**: still common in prod; upgrade via the Registry 5-to-6 guide
- Older: **4.x**: treat as debt; plan 4 to 5 before 5 to 6
- **3.x**: unsupported, do not run in production

## Step 2: Understand breaking changes before upgrading

Before you upgrade, read the changelog for each version you're skipping.

### Changelog structure

Each major version has a list of breaking changes:

```
AWS PROVIDER 5.0
- BREAKING CHANGE: aws_elasticache_cluster `engine_version` argument is now required

AWS PROVIDER 4.50
- NEW: aws_lambda_permission `qualifier` argument added
- DEPRECATED: aws_s3_bucket_website_configuration. Use aws_s3_bucket instead.
```

Breaking changes categories:

| Type                   | Example                                                         | Impact                                              |
| ---------------------- | --------------------------------------------------------------- | --------------------------------------------------- |
| Required arguments     | Field that was optional is now required                         | terraform plan will show errors                     |
| Renamed arguments      | `security_group_ids` renamed to `security_group_id_list`        | terraform apply will fail                           |
| Removed resources      | `aws_security_group_association` no longer exists               | terraform plan will show resource will be destroyed |
| Changed default values | Default `multi_az = false` is now `multi_az = true`             | terraform apply might replace resources             |
| Deprecated resources   | `aws_db_security_group` is deprecated; use `aws_security_group` | Works now, will be removed in future                |

### Document breaking changes specific to your infrastructure

Go through the changelog for each version you're upgrading through. Note which changes affect your infrastructure:

```markdown
# AWS Provider 5.0 Upgrade Breaking Changes

## Affects Our Infrastructure

1. aws_elasticache_cluster: engine_version now required
   - Current code: elasticache clusters without explicit version
   - Impact: Need to add engine_version to all elasticache resources

2. aws_s3_bucket: website property removed
   - Current code: 2 buckets use website property
   - Impact: Migrate to aws_s3_bucket_website_configuration

## Doesn't Affect Us

- aws_rds_db_instance: default backup_retention changed
  (We explicitly set retention; no issue)
```

## Step 3: Test the upgrade in a non-prod environment

![Architecture diagram of a Terraform provider constraint planned in staging before production](../../assets/images/blog/terraform-aws-provider-upgrade-strategy-stage.webp)

_Figure: the upgrade order in the article. Change one major constraint, plan it in a non-production environment, and apply production only after that plan is reviewed. The sample state bucket name is not shown. [Open the draw.io source](https://www.joinhorizon.co/examples/architecture-blog-2026/terraform-aws-provider-upgrade-strategy/stage.drawio)._

Never upgrade the provider on production first.

### Create a staging environment with identical configuration

```bash
# Staging configuration with same infrastructure
cd terraform/staging/

# Use the same code, but different AWS account/region
terraform {
  backend "s3" {
    bucket = "terraform-state-staging"
    key    = "terraform.tfstate"
  }
}
```

### Update the provider version in staging only

```hcl
# terraform/staging/provider.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"  # Upgraded from 4.50
    }
  }
}
```

### Run plan and review

```bash
terraform init  # Downloads new provider
terraform plan  # Compares code against new provider
```

If `terraform plan` shows errors, you've found breaking changes. Debug them now, before touching production.

**Common error patterns:**

```
Error: Missing required argument
  on main.tf line 10, in resource "aws_elasticache_cluster" "cache":
  10: resource "aws_elasticache_cluster" "cache" {

    The argument "engine_version" is required, but was not set.
```

This tells you: upgrade broke this resource because you didn't specify `engine_version`. Add it:

```hcl
resource "aws_elasticache_cluster" "cache" {
  engine_version = "7.0"  # Add this
  # ... rest of config
}
```

### Fix breaking changes in code

For each breaking change:

1. Identify the resource and argument that broke
2. Update the Terraform code
3. Re-run `terraform plan` and verify the fix
4. Commit the fix to git

Example commit messages:

```
provider: upgrade aws to 5.0

- add engine_version to elasticache_cluster resources
- migrate s3 bucket website config to aws_s3_bucket_website_configuration
- add required multi_az argument to rds instances
```

### Verify staging still works

Once the plan shows no changes, verify staging infrastructure is still functional:

- SSH to staging servers (if applicable)
- Run health checks against staging databases
- Test staging applications
- Verify logs are clean (no warnings about deprecated features)

## Step 4: One major version at a time

Don't jump from 4.0 to 5.0 to 6.0 in one go. Upgrade one major version at a time.

Why:

- Breaking changes compound. Jumping multiple versions means multiple sets of breaking changes to handle
- If something breaks, you won't know which upgrade caused it
- Testing is simpler with single-version upgrades

Example safe progression:

```
Current: 4.50
Step 1: Latest 4.x patch → staging → prod
Step 2: 5.x major (changelog + staging) → prod
Step 3: 6.x major (refresh-only before region refactors) → prod

Current target (July 2026): 6.x pin with committed lockfile
```

## Step 5: Update the lock file and commit

Once staging tests pass, update the lock file:

```bash
cd terraform/

# Update provider version constraint
# Edit terraform.tf with new version

terraform init  # Updates lock file
```

Commit:

```bash
git add terraform.tf .terraform.lock.hcl
git commit -m "provider: upgrade aws to 5.0

- update provider version constraint
- add engine_version to elasticache resources
- refactor s3 website configs

Tested in staging environment. No infrastructure changes required."
```

## Step 6: Deploy to production

Once code is merged and tested, deploy to production:

### Option 1: Rolling Deployment (Safest)

1. Update provider version on one service or region
2. Monitor for 1 week
3. If stable, roll out to next service/region
4. Repeat until all environments updated

### Option 2: Blue-Green Deployment

1. Spin up new infrastructure with new provider version
2. Run integration tests
3. Switch traffic from old to new
4. Tear down old infrastructure

### Option 3: Direct Deployment with Approval Gates

1. Update provider version
2. Run `terraform plan` in CI/CD
3. Require senior engineer approval
4. Deploy via automated CI/CD

## Rolling back if the upgrade breaks production

![Architecture diagram of a production Terraform apply returning to the previous provider version](../../assets/images/blog/terraform-aws-provider-upgrade-strategy-revert.webp)

_Figure: the first rollback in the article. Put the previous provider constraint back, init, and plan. A clean plan is the gate before apply. Repairing state is the fallback when that revert is not enough. [Open the draw.io source](https://www.joinhorizon.co/examples/architecture-blog-2026/terraform-aws-provider-upgrade-strategy/revert.drawio)._

If the upgrade causes problems in production, you need to roll back quickly.

### Rollback option 1: Revert the provider version

If the new provider causes problems:

```hcl
# terraform.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.50"  # Revert to previous version
    }
  }
}
```

```bash
terraform init  # Re-download old provider
terraform plan  # Should show zero changes

# If plan is clean, apply
terraform apply
```

This should be fast (under 5 minutes) and straightforward.

### Rollback option 2: Use Terraform state to fix

If reverting the provider version doesn't work, you may need to repair state:

```bash
# Save current broken state
terraform state pull > broken-state.json

# Restore previous state from backup
# (You do have backups, right?)
terraform state push previous-state.json

# Plan to verify
terraform plan
```

This is riskier because you're trusting your state backup is accurate.

### Prevention: test breaking changes first

The best rollback is the one you never need:

1. Test all provider upgrades in staging first
2. Run integration tests (not just `terraform plan`)
3. Deploy to production during business hours (not Friday at 5 PM)
4. Have a senior engineer on-call
5. Keep the old provider version available for quick rollback

## Provider upgrade checklist

```markdown
## AWS Provider Upgrade (repeat per major: 4→5, then 5→6)

- [ ] Review Registry upgrade guide + changelog for the **next** major only
- [ ] Document breaking changes specific to our infrastructure
- [ ] Update provider version in staging environment only
- [ ] Run `terraform plan` in staging
- [ ] Fix all breaking changes in code
- [ ] Test staging infrastructure is functional
- [ ] Commit code changes to git
- [ ] Create PR with detailed description of changes
- [ ] PR review + approval from senior engineer
- [ ] Merge to main branch
- [ ] Run `terraform plan` in production (CI/CD)
- [ ] Verify plan shows zero changes
- [ ] Deploy to production via CI/CD with approval gate
- [ ] Monitor production for 24 hours
- [ ] Verify logs show no deprecation warnings
- [ ] Document upgrade in CHANGELOG/release notes
```

## Preventing drift from old provider versions

Old providers often have bugs that are fixed in newer versions. When you stay on old providers, you accumulate drift over time.

**Example:** AWS provider 4.0 had a bug where it didn't detect certain RDS property changes. You'd make a change in the console, and Terraform wouldn't notice. By provider 5.0, the bug was fixed, and suddenly Terraform detects the drift.

To prevent this:

1. Upgrade provider versions regularly (every 6 months)
2. Always read the changelog (bugs fixed = potential drift detected)
3. Run `terraform plan` after upgrades to discover drift
4. Address drift immediately (don't let it accumulate)

## What to do this week

1. Print the lockfile AWS provider version and constraint.
2. If you are on 4.x, schedule **4 to 5** only; if on 5.x, open the **6.x** upgrade guide and list resources you actually use.
3. Run the [checklist](https://www.joinhorizon.co/examples/architecture-blog-2026/terraform-provider-upgrade/aws-provider-major-upgrade-checklist.md) in a non-prod workspace. No multi-major jumps.

## What this post doesn't cover

OpenTofu provider forks, module-by-module version skew across many repos, and HCP Terraform run-task policy packs. Use your org’s module registry conventions for those.

---

## Related reading

- [Terraform State Management on AWS: Imports, State Moves, and Emergency Repairs](https://www.joinhorizon.co/blog/terraform-state-management-aws-import-move-repair/)
- [AWS Infrastructure Drift Detection: How to Find and Fix Config Drift Before It Breaks Production](https://www.joinhorizon.co/blog/aws-infrastructure-drift-detection-terraform/)
- [How to Build a Safe Terraform Apply Workflow on AWS: Approval Gates, Plan Review, and Rollback](https://www.joinhorizon.co/blog/safe-terraform-apply-workflows-approval-gates-aws/)

---

*Source: https://www.joinhorizon.co/blog/terraform-aws-provider-upgrade-strategy/*
