Terraform workspaces are useful for storing different environment configurations in the same backend. To allow changes to the configuration based on the current workspace the workspace name can be refrenced using terraform.workspace.

The immidiate approach to have different environmental settings would be to use a tenary operation on the current workspace i.e.

resource "aws_instance" "vm-1" {
  ami = (terraform.workspace == "staging"
    ? "ami-0b6d8a6db0c665fb7" # 18.04 LTS
    : "ami-05c26ae4789875080" # 20.04 LTS
  )
  instance_type = (terraform.workspace == "production"
    ? "m5.large"
    : "t3.large"
  )
}

Using this method not only reduces readability but also makes reasoning harder as it’s not easy to directly infer the configuration of a specific environment as well as default values.

In contrast input variables can be used alter the configuration without changing the source code. The values for these variables can be provided through different methods. One of them being a custom variable file (.tfvars) using the command line flag -var-file, which allows the user to create different environment configurations and have the environmental settings in a single location.

Their exists feature requests for automatically loading variables from a variable file based on the current workspace. Fortunately their exist multiple workarounds. One does this by using a local nested map where the keys of the outer map match the terraform.workspace name i.e.

locals {
  env = merge(local.vars["defaults"], local.vars[terraform.workspace])
  vars = {
    defaults = {
      instance_type = "t3.large"
    }

    staging = {
      ami = "ami-05c26ae4789875080" # 20.04 LTS
    }

    production = {
      ami           = "ami-0b6d8a6db0c665fb7" # 18.04 LTS
      instance_type = "m5.large"
    }
  }
}

resource "aws_instance" "vm-1" {
  ami           = local.env["ami"]
  instance_type = local.env["instance_type"]
}