The Terraform lookup
function helps maintain clean, DRY, and reusable code. In this blog, we'll explore the various scenarios where the lookup
function can be used, and provide some practical examples for both common and more advanced use cases.
Disclaimer
All use cases of Terraformlookup
function discussed here work similarly in OpenTofu, the open-source Terraform alternative. However, to keep it simple and familiar for DevOps engineers, we will refer to these as Terraformlookup
throughout this blog post.
What is Terraform Lookup Function
The Terraform lookup
function is used to retrieve a specific value from a Terraform map based on a particular key.
For instance, you can use lookup
to dynamically fetch the configuration values for your AWS instance based on the environment in which you want it to be deployed.
Syntax of Terraform Lookup Function
The syntax for the Terraform lookup
function accepts three arguments: map, key, and default_value, like so:
lookup(map, key, default_value)
Breaking things down, this is what each of these arguments means:
- map: The map variables containing the key-value pairs
- key: The key for which the value will be fetched from the map
- default_value: The value returned if the map does not contain the key
To demonstrate how these come together, let’s look at VPC ID allocation, where we have a string map vpc_ids
.
Using the code below, you can select the VPC using the lookup
function based on the environment, such as dev and prod:
variable "vpc_ids" {
type = map(string)
default = {
dev = "vpc-1ae23bn342cd"
staging = "vpc-1ae23bn34ecd"
prod = "vpc-1aa23bn342cd"
}
}
resource "aws_vpc" "selected" {
id = lookup(var.vpc_ids, ”prod”, "vpc-default")
}
Use Cases for Terraform Lookup Function
You can utilize the Terraform lookup
function in various scenarios, such as with dynamic keys, custom values, and more. Let’s explore them:
- If you have a map of environment-specific configurations (like ‘production’ and ‘development’), and you want to provide a default value for when a specific key is not found, you can pass the default value in the
lookup
function to your resources - If you want to manage different configurations for multiple environments, you can use the
lookup
function as it can handle nested maps like a map of string maps - If you want to pass the custom value for the region in your Terraform code, you can use
lookup
to map custom values to internal identifiers or configurations - You can allocate resources dynamically using the Terraform lookup function, such as passing the
instance_type
for theaws_instance
resource based on the environment
Now that we have a broad idea of how lookup
works and its use cases, let’s dive in a bit into the Terraform map to understand how values are retrieved.
The default_key Argument
Importantly, the default_value
argument helps avoid failures in cases where the key is not present. This makes Terraform lookup
a better alternative to var
and local
which accept static values and cannot handle failures.
Terraform lookup
is a better fit when trying to dynamically access values based on the input value or condition, providing an easier and more fault-proof way to manage your Terraform configuration.
A bit About Terraform Map
To understand how lookup
works, it’s also important to have a quick discussion about the Terraform map.
In short, Terraform map is a data structure that stores a collection of key-value pairs. It is used to store related data and write reusable code, making it easier to manage Terraform configurations.
Maps can be combined with other data structures. Some of these are:
- map(string): Map contains ‘string’ type values
- map(number): Map contains ‘number’ (integer or floating-point) type values
- map(bool): Map contains ‘bool’ (true or false) type values
- map(list): Map contains list (arrays) type values containing elements of the same type
- map(set): Map contains set type values containing unique elements of the same type
- map(object({ ... })): Map contains objects (complex data structures) type values that must conform to a specific structure defined by the object’s attributes
To explain how to use the Terraform map in your Terraform configuration, let’s take a look at this example where we have defined a map variable instance_size
containing the ‘string’ type values.
variable "instance_size" {
type = map(string)
default = {
t2.micro = "small"
t2.medium= "medium"
t2.large = "large"
}
}
Using the Terraform CLI, we will test how we can get the values in the map variable for the specified key using the syntax: map["key"]
. Here, the key “t2.micro”
gives you the value small
.
$ env0 git : (main) x terraform console
> var.instance_size[“t2.micro”]
"small
Examples of How to use the Lookup Function
The lookup
function is particularly useful for managing infrastructure configurations in Terraform. Let us do some hands-on exercises to understand it.
Terraform Lookup with a Map of String
We will start with defining a ‘s3_buckets’ variable to store the s3 bucket configurations, and the ‘environment’ variable to store the environment for which you want to get the s3 bucket configuration in your var.tf file.
variable "environment" {
type = string
default = "production"
}
variable "s3_buckets" {
type = map(string)
default = {
development = "myapp-dev-bucket"
staging = "myapp-staging-bucket"
production = "myapp-prod-bucket"
}
}
Next, we will create a aws_s3_bucket
resource for the production environment with the s3 bucket name myapp-prod-bucket
using the lookup
function in your Terraform configuration main.tf file.
resource "aws_s3_bucket" "s3_bucket" {
bucket = lookup(var.s3_buckets, var.environment, "default-bucket-name")
}
As per the lookup
function above, you can check the name of the s3_bucket
by running the terraform console
command in your terminal.
$ env0 git : (main) x terraform init
$ env0 git : (main) x terraform plan
$ env0 git : (main) x terraform console
> aws_s3_bucket.s3_bucket
"myapp-prod-bucket”
Terraform Lookup with an Object Map
Here we will start with creating a Terraform configuration in the var.tf file, defining a instance_configs
variable which stores the instance_type
based on the different environments (development, production).
In addition, we will also define the ‘environment’ variable to store the development
value for which we will create the aws_instance
:
variable "environment" {
type = string
default = "development"
}
variable "instance_configs" {
type = map(object({
instance_type = string
}))
default = {
development = {
instance_type = "t2.micro"
}
production = {
instance_type = "m5.large"
}
}
}
Deploying the aws_instance
for the development environment using the lookup
function will fetch the lighter instance_type
, based on the value of the environment
variable.
resource "aws_instance" "dev_instance" {
instance_type = lookup(var.instance_configs[var.environment], "instance_type", "t3.micro")
ami = "ami-0c55b159cbfafe1f0"
}
To see that it works, you can verify that the value of the instance_type
is t2.micro
by using the terraform console:
$ env0 git : (main) x terraform init
$ env0 git : (main) x terraform plan
$ env0 git : (main) x terraform console
> aws_instance.dev_instance.instance_type
"t2.micro"
Lookup Function When No Key Value is Found
Now, still using the above example, let’s assume that you would like to change the value for the environment
variable to ‘integration’.
Since it does not exist, the value of the instance_type
will change to the default value passed in the lookup
function, which is t3.micro
.
Again, you can verify this by using the Terraform console in your terminal:
$ env0 git : (main) x terraform init
$ env0 git : (main) x terraform plan
$ env0 git : (main) x terraform console
> aws_instance.dev_instance.instance_type
"t3.micro"
Terraform Lookup with Nested Map
Here, you will configure the ami
and the instance_type
for an aws_instance
resource using the Terraform lookup
function with a map of string maps.
First, let's define an instance_config
variable, a “map of maps” containing string values for ami
and instance_type
for the development and production environment in the var.tf file.
Next, we will create an ‘environment’ variable to store the value of the environment for which you would like to create the aws_instance
:
variable "instance_config" {
type = map(map(string))
default = {
development = {
ami = "ami-0abcdef1234567890"
instance_type = "t2.micro"
}
production = {
ami = "ami-1234567890abcdef0"
instance_type = "t2.large"
}
}
}
variable "environment" {
type = string
default = "development"
}
Now, let us filter the ami
and instance_id
using the Terraform lookup
function in the nested form and deploy an aws_instance
in the main.tf file.
resource "aws_instance" "ec2" {
ami = lookup(lookup(var.instance_config, var.environment), "ami")
instance_type = lookup(lookup(var.instance_config, var.environment), "instance_type")
}
You can check the value for the aws_instance
resource using the Terraform console in your terminal:
$ env0 git : (main) x terraform init
$ env0 git : (main) x terraform plan
$ env0 git : (main) x terraform console
> aws_instance.ec2.instance_type
"t2.micro"
> aws_instance.ec2.ami
"ami-0abcdef1234567890"
Best Practices of Using Terraform Lookup Function
Here are some of the best practices you should follow while using the Terraform lookup
function:
- Always make sure to provide the default value in the
lookup
function to handle a failure scenario where the key is not present in the map - Avoid the type mismatch error by maintaining the consistency of the map value type and the default value in the
lookup
function - Verify the existence of the key in the input map of the
lookup
function by using thecontains
function to ensure that the correct configuration value is passed - Make your code more flexible and maintainable using variables or dynamic expressions instead of hardcoding the keys so that you can change them easily
Terraform Lookup with env0
With env0's Custom Workflow capabilities, you can automate the deployment process, manage environment variables, and efficiently build a secure, reliable infrastructure using best practices.
This section will walk you through the process of leveraging env0’s environment variables with the Terraform lookup
function, to deploy EC2 instances based on the environment.
Step 1: Define the Terraform Configuration
Let’s set up the AWS provider in your provider.tf file:
provider "aws" {
region = var.region
access_key = var.access_key
secret_key = var.secret_key
}
Step 2: Define Variables
Define your variables in the var.tf file. The environment
variable will allow you to customize your infrastructure based on dev or prod environments.
variable "region" {
type = string
}
variable "access_key" {
type = string
}
variable "secret_key" {
type = string
}
variable "environment" {
type = string
default = "dev"
}
Step 3: Define Local Values Using Terraform Lookup Function
You can pass the value to instance_type
using the lookup
function, where you can dynamically select the instance_types
based on the environment in locals.tf.
locals {
instance_types = {
dev = "t2.micro"
prod = "t3.medium"
}
instance_type = lookup(local.instance_types, var.environment, "t2.micro")
}
Step 4: Create EC2 Instance
You can create AWS EC2 instances based on a dynamically generated list of instance_names
in your main.tf file.
resource "aws_instance" "Infrasity" {
ami = "ami-068e0f1a600cd311c"
instance_type = local.instance_type
tags = {
Name = "Instance-1"
Environment = var.environment
}
}
Step 5: Integrate with env0
Now, we will integrate our Terraform configuration with env0 by following these steps:
- Create Environment: Go to 'CREATE NEW ENVIRONMENT' under your project in env0
- Connect GitHub Repository: Connect the GitHub repository to env0, where your Terraform code is stored remotely
- Configure Environment Variables: Navigate to the environment in env0. Go to the Settings tab. Under ‘Environment Variables’, add the following variables:
- ‘TF_VAR_region’: Set this to your desired AWS region
- ‘TF_VAR_access_key’: Enter your AWS access key
- ‘TF_VAR_secret_key’: Enter your AWS secret key
- ‘TF_VAR_environment’: Specify the environment type, either dev or prod
- Deploy the Environment: You can deploy your environment from the env0 dashboard. To start the deployment process, either click on 'Run Deploy' or save the environment variables. The process states are shown in the Deployment-Logs section.
After successfully deploying your infrastructure, you can check the instances via the AWS console:
Meanwhile, the Terraform lookup
function enables dynamic and flexible configuration management to control and customize infrastructure variables and settings.
With env0, you can efficiently manage your Terraform environments, apply changes, and monitor your infrastructure using one tool, as you also follow best practices.
Conclusion
By now, you should have a clear understanding of the functionality of the Terraform lookup
function and its use cases.
We looked at how to use the Terraform lookup
function with simple or complex Terraform map types and how to use env0’s capabilities with the Terraform lookup
function to manage infrastructure effectively.
Frequently Asked Questions
Q. What is the alternative to lookup in Terraform?
The lookup
function alternative is the element
function. The key distinction between these functions lies in the type of object they target. The element
function is designed to iterate over and retrieve values from a list, whereas the lookup
function is aimed at maps.
Q. What happens if the specified key is not found in the map?
If the specified key is not present in the map, the Terraform lookup
function will return the default value.
Q. Can I use the lookup function with lists or arrays?
The Terraform lookup
function cannot be used with a list or array. It is specifically designed for map and object data structures. However, you can access elements within a list using the element
function.
Q. Is the Terraform lookup function available for all versions of Terraform?
You can utilize the lookup
function in Terraform version 0.12 and above. For earlier versions, you may need to use the map
and element
functions to achieve similar results.
Q. What is the difference between the Terraform lookup and try function?
Let’s look at the difference between Terraform lookup
and try
function, which are often mentioned together, with try being a more general form of lookup, preferred by some for its simplicity:
Top comments (2)
Thank you for writing this article; I thoroughly enjoyed it! I've been using Terraform daily for quite some time now and consider myself nearing expert level, but I hadn't come across this function before. I appreciate the insight!
Thank you @whimsicalbison!