Default tag configuration in the Terraform AWS provider represents a mechanism for enforcing consistent metadata across infrastructure as code without requiring repetitive declaration on every resource. The feature arrived with Terraform AWS Provider v3.38.0 and applies to all taggable resources created by the provider, with the explicit exception of Auto Scaling Groups. The introduction of provider-level defaults changes how teams implement AWS recommended tagging for auditing, cost allocation and access control, and it creates a distinct set of behaviors around inheritance, precedence, and workarounds for resources that do not support automatic propagation.
The Terraform AWS provider contains over 700 resources to standardize AWS infrastructure configuration in accordance with best practices. The ability to define default tags at the provider level was one of the most common requests for the provider. As of v3.38.0 of the Terraform AWS provider, users are able to define default tags for all resources except Auto Scaling Groups. The feature relies on a provider block configuration that is evaluated at plan time and merged with resource-level tag blocks.
Tags are the foundation of AWS cost management, access control, and operational visibility. Without consistent tagging, organizations end up with resources they cannot attribute to teams, costs they cannot allocate, and compliance gaps they cannot close. Tagging is usually an afterthought where a resource is created without tags and an untagged EC2 instance consumes budget with no owner. Terraform's default_tags feature, combined with validation and organizational policies, solves this problem at the infrastructure level by making tagging a default property of resource creation rather than an opt-in step.
AWS recommends that users define a robust and consistent tagging strategy to enable better auditing, cost, and access control for AWS resources. The AWS Terraform provider v3.38.0+ allows users to add default tags to all resources that the provider creates, making it easier to implement a consistent tagging strategy for all of the AWS resources managed with Terraform. The tutorial workflow for this configuration can be completed using Terraform Community Edition or HCP Terraform. HCP Terraform is a platform that can be used to manage and execute Terraform projects and includes features like remote state and execution, structured plan output, and workspace resource summaries.
Provider-Level default_tags Configuration
Provider-level defaulttags is configured inside the aws provider block using a nested defaulttags block with a tags map.
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
Project = var.project_name
ManagedBy = "terraform"
Team = var.team_name
CostCenter = var.cost_center
}
}
}
Every supported AWS resource created by that provider automatically inherits these tags. The configuration shown above applies five tags to every taggable resource. The provider block shown in reference material also uses static values:
provider "aws" {
default_tags {
tags = {
Environment = "Test"
Owner = "TFProviders"
Project = "Test"
}
}
}
In order to configure default tags the following prerequisites are required:
- Terraform 0.12 or later
- Terraform AWS Provider v3.38.0 or later
Setting default tags at the provider level will not supersede tags set on individual resources as resource tags take precedence. Any tags set in the provider block will also be inherited by dependent Terraform modules.
The merged result is available via tags_all on any resource. The provider-level block applies tags automatically to all supported resources, and any resource-level tags are merged on top, with resource-level values winning on key conflicts.
Inheritance Behavior and Merge Precedence
The default_tags block in the provider applies tags automatically to all supported resources. Resource-level tags are merged on top of provider defaults. When a key conflict exists, the resource-level value wins.
An example of merge behavior is shown with an S3 bucket:
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
Environment = "production"
ManagedBy = "terraform"
Owner = "platform-team"
}
}
}
resource "aws_s3_bucket" "example" {
bucket = "my-app-assets"
tags = {
Purpose = "static-assets"
}
}
The bucket will carry four tags in total, three from defaulttags and one from the resource block. The merged result is inspectable via tagsall.
An example of explicit merge using variables is:
variable "default_tags" {
default = {
Environment = "Production"
ManagedBy = "Terraform"
}
}
resource "aws_instance" "example" {
ami = "ami-0c94855ba95c71c99"
instance_type = "t2.micro"
tags = merge(
var.default_tags,
{
Name = "ExampleInstance"
Project = "MyApp"
}
)
}
The merge function combines the default_tags variable with additional resource-specific tags, resulting in all four tags being applied to the EC2 instance.
Terraform allows tags to be defined as variables and use functions like merge to combine them with other tags, promoting reusability and flexibility.
Auto Scaling Group Tagging Limitations
Default tags do not apply to all resources. Most notably, awsautoscalinggroup does not pick them up automatically. This is because ASGs dynamically create EC2 instances outside Terraform's direct management, so the provider cannot propagate defaults to the launched instances.
Due to the dynamic nature of Auto Scaling Groups, they behave differently than other AWS resources. The tags include the default ASG tags but not the default tags from the provider configuration.
The main exception documented for the defaulttags feature is awsautoscaling_group, which needs tags configured on the resource itself.
AWS imposes a limit of 50 tags per resource.
Workarounds Using locals and merge
In order to set default tags for AWS Auto Scaling Groups, a standard workaround is to set locals with the default tag and then merge that into the Auto Scaling group.
A variable definition for this pattern is:
variable "default_tags" {
default = {
Environment = "Test"
Owner = "TFProviders"
Project = "Test"
}
description = "Default Tags for Auto Scaling Group"
type = map(string)
}
The resource configuration combines default tags with optionally provided additional tags:
resource "aws_autoscaling_group" "example" {
tags = merge(
var.default_tags,
{
Name = "MyASG"
},
)
}
This configuration maintains benefits of default tags while gaining flexibility to customize tags based on specific needs of individual resources.
Another documented workaround is to use the awsdefaulttags data source with a dynamic tag block on the ASG, or to define a local and merge it explicitly into each resource.
When the tags are not correctly applied to instances launched by an ASG, reprovisioning may be required:
$ terraform apply -replace aws_autoscaling_group.example
The replace option forces Terraform to reprovision the Auto Scaling group and launch a new instance with the appropriate tags.
Launch Template tag_specifications and Propagation
Some AWS resources require specific tagging configurations or have limitations on how tags can be applied. Without the right configuration, the EC2 instance and attached storage volumes launched by the ASG and launch template will not have the default tags attached.
ASGs require the propagateatlaunch tag configuration.
Launch templates require the tag_specifications configuration:
resource "aws_launch_template" "example" {
tag_specifications {
resource_type = "instance"
tags = {
Environment = "Production"
ManagedBy = "Terraform"
}
}
tag_specifications {
resource_type = "volume"
tags = {
Persistence = "Permanent"
}
}
}
When you create Elastic Compute EC2 instances via Terraform, the tagging of the instance and volumes must be explicitly declared in the launch template tag specifications.
Provider Support Comparison
Understanding how each provider handles defaults, inheritance, and naming constraints prevents subtle misconfigurations that are easy to miss in a plan.
AWS has the most complete tagging support of the three major providers. The default_tags block in the provider applies tags automatically to all supported resources, and any resource-level tags are merged on top, with resource-level values winning on key conflicts.
The AzureRM provider v4.x does not support provider-level default tags. Every resource must define its tags explicitly using the tags block.
Default Tag Specification Table
| Aspect | Detail |
| Requirement | Terraform 0.12 or later and Terraform AWS Provider v3.38.0 or later |
| Configuration Location | provider "aws" block with defaulttags { tags = { ... } } |
| Inheritance | Inherited by dependent Terraform modules |
| Precedence | Resource-level tags override provider defaults |
| Exception | awsautoscalinggroup does not inherit automatically |
| Visibility | Merged result available via tagsall attribute |
| Tag Limit | 50 tags per resource imposed by AWS |
Resource Examples
VPC example with resource-level tag merging:
resource "aws_vpc" "example" {
cidr_block = "10.1.0.0/16"
tags = {
Name = "my-vpc-resource"
}
}
Subnet example:
resource "aws_subnet" "example" {
cidr_block = "10.1.1.0/24"
vpc_id = aws_vpc.test.id
tags = {
Name = "my-subnet-resource"
}
}
Default tags set at provider level are merged with these resource tags, with resource tags taking precedence on conflict.
Conclusion
Default tags in the Terraform AWS provider provide a centralized enforcement point for organizational tagging standards. The provider-level defaulttags block introduced in v3.38.0 ensures that every taggable resource created by the provider carries a baseline set of metadata for Environment, Project, Owner, ManagedBy, Team, CostCenter and other keys. Resource-level tags merge on top of those defaults with resource values winning on key conflicts, and the merged set is observable via tagsall.
The design creates immediate operational impact by eliminating untagged resources that escape cost allocation and access control. It also reduces repetition across modules because provider defaults propagate into dependent Terraform modules.
The Auto Scaling Group exception remains a critical boundary. Because ASGs create EC2 instances dynamically outside Terraform's direct management, provider defaults do not reach the launched instances. This forces explicit workarounds using merge with variables or locals, propagateatlaunch settings, and launch template tag_specifications for instance and volume tagging. The need to reprovision an ASG with -replace to apply corrected tags illustrates the cost of misconfiguration.
The 50 tag per resource limit imposed by AWS adds a practical ceiling to how many defaults and resource-specific tags can coexist. Teams must design tag schemas with that limit in mind while using default_tags to guarantee baseline coverage.
Overall, default_tags succeeds as a standardisation mechanism for the majority of AWS resources, and the documented workarounds for ASGs and launch templates preserve tag consistency across the dynamic parts of the AWS control plane.