• Overview
    • Enforce Policy as Code
    • Infrastructure as Code
    • Inject Secrets into Terraform
    • Integrate with Existing Workflows
    • Manage Kubernetes
    • Manage Virtual Machine Images
    • Multi-Cloud Deployment
    • Network Infrastructure Automation
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
  • Registry
  • Tutorials
    • About the Docs
    • Intro to Terraform
    • Configuration Language
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
    • Provider Use
    • Plugin Development
    • Registry Publishing
    • Integration Program
    • Terraform Tools
    • CDK for Terraform
    • Glossary
  • Community
GitHubTerraform Cloud
Download

    Terraform Language

  • Overview
  • Attributes as Blocks - Configuration Language
  • Terraform v1.0 Compatibility Promises
    • Overview
    • Override Files
    • Dependency Lock File
    • Overview
    • Configuration Syntax
    • JSON Configuration Syntax
    • Style Conventions
    • Overview
    • Resource Blocks
    • Resource Behavior
      • depends_on
      • count
      • for_each
      • provider
      • lifecycle
      • Declaring Provisioners
      • Provisioner Connections
      • Provisioners Without a Resource
      • file
      • local-exec
      • remote-exec

      • chef
      • habitat
      • puppet
      • salt-masterless
  • Data Sources
    • count
    • depends_on
    • for_each
    • lifecycle
    • providers
    • provider
    • Overview
    • Provider Configuration
    • Provider Requirements
    • Dependency Lock File
    • Overview
    • Input Variables
    • Output Values
    • Local Values
    • Overview
    • Module Blocks
    • Module Sources
      • providers
      • depends_on
      • count
      • for_each
      • Overview
      • Standard Module Structure
      • Providers Within Modules
      • Best Practices: Module Composition
      • Publishing Modules
      • Refactoring Modules
    • Module Testing Experiment
    • Overview
    • Types and Values
    • Strings and Templates
    • References to Values
    • Operators
    • Function Calls
    • Conditional Expressions
    • For Expressions
    • Splat Expressions
    • Dynamic Blocks
    • Custom Condition Checks
    • Type Constraints
    • Version Constraints
    • Overview
      • abs
      • ceil
      • floor
      • log
      • max
      • min
      • parseint
      • pow
      • signum
      • chomp
      • format
      • formatlist
      • indent
      • join
      • lower
      • regex
      • regexall
      • replace
      • split
      • strrev
      • substr
      • title
      • trim
      • trimprefix
      • trimsuffix
      • trimspace
      • upper
      • alltrue
      • anytrue
      • chunklist
      • coalesce
      • coalescelist
      • compact
      • concat
      • contains
      • distinct
      • element
      • flatten
      • index
      • keys
      • length
      • list
      • lookup
      • map
      • matchkeys
      • merge
      • one
      • range
      • reverse
      • setintersection
      • setproduct
      • setsubtract
      • setunion
      • slice
      • sort
      • sum
      • transpose
      • values
      • zipmap
      • base64decode
      • base64encode
      • base64gzip
      • csvdecode
      • jsondecode
      • jsonencode
      • textdecodebase64
      • textencodebase64
      • urlencode
      • yamldecode
      • yamlencode
      • abspath
      • dirname
      • pathexpand
      • basename
      • file
      • fileexists
      • fileset
      • filebase64
      • templatefile
      • formatdate
      • timeadd
      • timestamp
      • base64sha256
      • base64sha512
      • bcrypt
      • filebase64sha256
      • filebase64sha512
      • filemd5
      • filesha1
      • filesha256
      • filesha512
      • md5
      • rsadecrypt
      • sha1
      • sha256
      • sha512
      • uuid
      • uuidv5
      • cidrhost
      • cidrnetmask
      • cidrsubnet
      • cidrsubnets
      • can
      • defaults
      • nonsensitive
      • sensitive
      • tobool
      • tolist
      • tomap
      • tonumber
      • toset
      • tostring
      • try
      • type
    • abs
    • abspath
    • alltrue
    • anytrue
    • base64decode
    • base64encode
    • base64gzip
    • base64sha256
    • base64sha512
    • basename
    • bcrypt
    • can
    • ceil
    • chomp
    • chunklist
    • cidrhost
    • cidrnetmask
    • cidrsubnet
    • cidrsubnets
    • coalesce
    • coalescelist
    • compact
    • concat
    • contains
    • csvdecode
    • defaults
    • dirname
    • distinct
    • element
    • file
    • filebase64
    • filebase64sha256
    • filebase64sha512
    • fileexists
    • filemd5
    • fileset
    • filesha1
    • filesha256
    • filesha512
    • flatten
    • floor
    • format
    • formatdate
    • formatlist
    • indent
    • index
    • join
    • jsondecode
    • jsonencode
    • keys
    • length
    • list
    • log
    • lookup
    • lower
    • map
    • matchkeys
    • max
    • md5
    • merge
    • min
    • nonsensitive
    • one
    • parseint
    • pathexpand
    • pow
    • range
    • regex
    • regexall
    • replace
    • reverse
    • rsadecrypt
    • sensitive
    • setintersection
    • setproduct
    • setsubtract
    • setunion
    • sha1
    • sha256
    • sha512
    • signum
    • slice
    • sort
    • split
    • strrev
    • substr
    • sum
    • templatefile
    • textdecodebase64
    • textencodebase64
    • timeadd
    • timestamp
    • title
    • tobool
    • tolist
    • tomap
    • tonumber
    • toset
    • tostring
    • transpose
    • trim
    • trimprefix
    • trimspace
    • trimsuffix
    • try
    • type
    • upper
    • urlencode
    • uuid
    • uuidv5
    • values
    • yamldecode
    • yamlencode
    • zipmap
    • Overview
    • Terraform Cloud
      • Backend Configuration
        • local
        • remote
        • artifactory
        • azurerm
        • consul
        • cos
        • etcd
        • etcdv3
        • gcs
        • http
        • Kubernetes
        • manta
        • oss
        • pg
        • s3
        • swift
      • local
      • remote
      • artifactory
      • azurerm
      • consul
      • cos
      • etcd
      • etcdv3
      • gcs
      • http
      • Kubernetes
      • manta
      • oss
      • pg
      • s3
      • swift
    • Overview
    • Purpose
    • The terraform_remote_state Data Source
    • Backends: State Storage and Locking
    • Import Existing Resources
    • Locking
    • Workspaces
    • Remote State
    • Sensitive Data
    • Overview
    • Upgrading to Terraform v1.2
    • Upgrading to Terraform v1.1
    • Upgrading to Terraform v1.0
    • v1.0 Compatibility Promises
    • Upgrading to Terraform v0.15
    • Upgrading to Terraform v0.14
    • Upgrading to Terraform v0.13
    • Upgrading to Terraform v0.12
    • Upgrading to Terraform v0.11
    • Upgrading to Terraform v0.10
    • Upgrading to Terraform v0.9
    • Upgrading to Terraform v0.8
    • Upgrading to Terraform v0.7
    • Overview
    • Load Order and Semantics
    • Configuration Syntax
    • Interpolation Syntax
    • Overrides
    • Resources
    • Data Sources
    • Providers
    • Variables
    • Outputs
    • Local Values
    • Modules
    • Terraform
    • Provisioners
    • Providers
    • Terraform Push (deprecated)
    • Environment Variables

  • Terraform Internals

  • Other Docs

  • Intro to Terraform
  • Configuration Language
  • Terraform CLI
  • Terraform Cloud
  • Terraform Enterprise
  • Provider Use
  • Plugin Development
  • Registry Publishing
  • Integration Program
  • Terraform Tools
  • CDK for Terraform
  • Glossary
Type '/' to Search

»defaults Function

Note: This function is available only in Terraform 0.15 and later.

Experimental: This function is part of the optional attributes experiment and is only available in modules where the module_variable_optional_attrs experiment is explicitly enabled.

The defaults function is a specialized function intended for use with input variables whose type constraints are object types or collections of object types that include optional attributes.

When you define an attribute as optional and the caller doesn't provide an explicit value for it, Terraform will set the attribute to null to represent that it was omitted. If you want to use a placeholder value other than null when an attribute isn't set, you can use the defaults function to concisely assign default values only where an attribute value was set to null.

defaults(input_value, defaults)
defaults(input_value, defaults)

The defaults function expects that the input_value argument will be the value of an input variable with an exact type constraint (not containing any). The function will then visit every attribute in the data structure, including attributes of nested objects, and apply the default values given in the defaults object.

The interpretation of attributes in the defaults argument depends on what type an attribute has in the input_value:

  • Primitive types (string, number, bool): if a default value is given then it will be used only if the input_value's attribute of the same name has the value null. The default value's type must match the input value's type.
  • Structural types (object and tuple types): Terraform will recursively visit all of the attributes or elements of the nested value and repeat the same defaults-merging logic one level deeper. The default value's type must be of the same kind as the input value's type, and a default value for an object type must only contain attribute names that appear in the input value's type.
  • Collection types (list, map, and set types): Terraform will visit each of the collection elements in turn and apply defaults to them. In this case the default value is only a single value to be applied to all elements of the collection, so it must have a type compatible with the collection's element type rather than with the collection type itself.

The above rules may be easier to follow with an example. Consider the following Terraform configuration:

terraform {
  # Optional attributes and the defaults function are
  # both experimental, so we must opt in to the experiment.
  experiments = [module_variable_optional_attrs]
}

variable "storage" {
  type = object({
    name    = string
    enabled = optional(bool)
    website = object({
      index_document = optional(string)
      error_document = optional(string)
    })
    documents = map(
      object({
        source_file  = string
        content_type = optional(string)
      })
    )
  })
}

locals {
  storage = defaults(var.storage, {
    # If "enabled" isn't set then it will default
    # to true.
    enabled = true

    # The "website" attribute is required, but
    # it's here to provide defaults for the
    # optional attributes inside.
    website = {
      index_document = "index.html"
      error_document = "error.html"
    }

    # The "documents" attribute has a map type,
    # so the default value represents defaults
    # to be applied to all of the elements in
    # the map, not for the map itself. Therefore
    # it's a single object matching the map
    # element type, not a map itself.
    documents = {
      # If _any_ of the map elements omit
      # content_type then this default will be
      # used instead.
      content_type = "application/octet-stream"
    }
  })
}

output "storage" {
  value = local.storage
}
terraform {
  # Optional attributes and the defaults function are
  # both experimental, so we must opt in to the experiment.
  experiments = [module_variable_optional_attrs]
}

variable "storage" {
  type = object({
    name    = string
    enabled = optional(bool)
    website = object({
      index_document = optional(string)
      error_document = optional(string)
    })
    documents = map(
      object({
        source_file  = string
        content_type = optional(string)
      })
    )
  })
}

locals {
  storage = defaults(var.storage, {
    # If "enabled" isn't set then it will default
    # to true.
    enabled = true

    # The "website" attribute is required, but
    # it's here to provide defaults for the
    # optional attributes inside.
    website = {
      index_document = "index.html"
      error_document = "error.html"
    }

    # The "documents" attribute has a map type,
    # so the default value represents defaults
    # to be applied to all of the elements in
    # the map, not for the map itself. Therefore
    # it's a single object matching the map
    # element type, not a map itself.
    documents = {
      # If _any_ of the map elements omit
      # content_type then this default will be
      # used instead.
      content_type = "application/octet-stream"
    }
  })
}

output "storage" {
  value = local.storage
}

To test this out, we can create a file terraform.tfvars to provide an example value for var.storage:

storage = {
  name = "example"

  website = {
    error_document = "error.txt"
  }
  documents = {
    "index.html" = {
      source_file  = "index.html.tmpl"
      content_type = "text/html"
    }
    "error.txt" = {
      source_file  = "error.txt.tmpl"
      content_type = "text/plain"
    }
    "terraform.exe" = {
      source_file  = "terraform.exe"
    }
  }
}
storage = {
  name = "example"

  website = {
    error_document = "error.txt"
  }
  documents = {
    "index.html" = {
      source_file  = "index.html.tmpl"
      content_type = "text/html"
    }
    "error.txt" = {
      source_file  = "error.txt.tmpl"
      content_type = "text/plain"
    }
    "terraform.exe" = {
      source_file  = "terraform.exe"
    }
  }
}

The above value conforms to the variable's type constraint because it only omits attributes that are declared as optional. Terraform will automatically populate those attributes with the value null before evaluating anything else, and then the defaults function in local.storage will substitute default values for each of them.

The result of this defaults call would therefore be the following object:

storage = {
  "documents" = tomap({
    "error.txt" = {
      "content_type" = "text/plain"
      "source_file"  = "error.txt.tmpl"
    }
    "index.html" = {
      "content_type" = "text/html"
      "source_file"  = "index.html.tmpl"
    }
    "terraform.exe" = {
      "content_type" = "application/octet-stream"
      "source_file"  = "terraform.exe"
    }
  })
  "enabled" = true
  "name" = "example"
  "website" = {
    "error_document" = "error.txt"
    "index_document" = "index.html"
  }
}
storage = {
  "documents" = tomap({
    "error.txt" = {
      "content_type" = "text/plain"
      "source_file"  = "error.txt.tmpl"
    }
    "index.html" = {
      "content_type" = "text/html"
      "source_file"  = "index.html.tmpl"
    }
    "terraform.exe" = {
      "content_type" = "application/octet-stream"
      "source_file"  = "terraform.exe"
    }
  })
  "enabled" = true
  "name" = "example"
  "website" = {
    "error_document" = "error.txt"
    "index_document" = "index.html"
  }
}

Notice that enabled and website.index_document were both populated directly from the defaults. Notice also that the "terraform.exe" element of documents had its content_type attribute populated from the documents default, but the default value didn't need to predict that there would be an element key "terraform.exe" because the default values apply equally to all elements of the map where the optional attributes are null.

»Using defaults elsewhere

The design of the defaults function depends on input values having well-specified type constraints, so it can reliably recognize the difference between similar types: maps vs. objects, lists vs. tuples. The type constraint causes Terraform to convert the caller's value to conform to the constraint and thus defaults can rely on the input to conform.

Elsewhere in the Terraform language it's typical to be less precise about types, for example using the object construction syntax { ... } to construct values that will be used as if they are maps. Because defaults uses the type information of input_value, an input_value that doesn't originate in an input variable will tend not to have an appropriate value type and will thus not be interpreted as expected by defaults.

We recommend using defaults only with fully-constrained input variable values in the first argument, so you can use the variable's type constraint to explicitly distinguish between collection and structural types.

github logoEdit this page
  • Overview
  • Docs
  • Extend
  • Privacy
  • Security
  • Press Kit
  • Consent Manager