In Terraform, many configurations are dynamic, and you may build a list using conditional expressions that return null
when not applicable. If those null
values are passed directly to a resource (for example, in security_group_ids
or depends_on
), they can cause validation errors.
The compact()
function ensures that only valid, non-null elements are included, helping prevent such runtime errors during the apply phase.
What is the Terraform compact function?
The compact()
function in Terraform removes null
and empty string (""
) elements from a list and returns a new list containing only non-empty, non-null string elements. It is part of Terraform's standard library and is especially useful when working with dynamic expressions that might introduce null values, such as conditional logic or interpolated variables.
The syntax is simple: compact(list)
, where list
is the input that may include null entries. For example, compact(["a", "", "b"])
returns ["a", "b"]
.
Note: The compact
function only removes null
and empty string (""
) elements. It does not remove other falsy values like false
, 0
, or empty lists ([]
).
When to use the compact function?
The compact function in Terraform helps create clean, reliable lists, especially in complex configurations that involve conditional logic or user inputs. Here are some common use cases:
- Conditional resource arguments - Use
compact()
to filter out nulls from lists with conditional elements, ensuring only valid values are passed. - Merging variable defaults and overrides - When combining lists from multiple sources,
compact()
removes nulls to produce clean, merged values. - Outputs or module arguments - Prevent errors in
terraform apply
by eliminating nulls from outputs or module inputs where only valid strings or IDs are expected. - Conditional inclusion in loops - Within a
for
loop, returnnull
for elements to skip, then wrap the expression withcompact()
to exclude them from the final list. - Simplified filtering logic - Replace external
if
conditions with inlinenull
returns in loop bodies, followed bycompact()
to simplify list filtering. For example:
Suppose var.names
is equal to ["Alice", "skip", "Bob", "skip", "Charlie"]
[for item in var.names : item != "skip" ? item : null] -> this will transform the list in ["Alice", null, "Bob", null, "Charlie"]
can become:
compact([for item in var.names : item == "skip" ? null : item]) -> this will transform the list in ["Alice", "Bob", "Charlie"]
💡 You might also like:
- Terraform Strings: Interpolation, Multiline & Built-in Functions
- Terraform Null Resource – What It is & How to Use It
- How to Use the If / Else Statement in Terraform – Examples
How to use the Terraform compact function
Here are six examples of using the compact
function, including some basic and more advanced ones.
One thing to remember before we move to the examples is that the compact()
function only works on lists where all elements are strings (or are coercible to strings). If you pass complex types like objects or numbers, Terraform may produce a type error.
Example 1: Removing null from a simple list
This example shows a static list with some null
values. The compact()
function scans the list and filters out any null
and ""
entries, returning only ["value1", "value2", "value3"]
.
variable "input_list" {
default = ["value1", null, "value2", null, "value3"]
}
output "cleaned_list" {
value = compact(var.input_list)
}
This is the most straightforward use case and often appears in variable preprocessing.
Example 2: Dynamic list with conditional values
Here, the list includes a conditional value that may evaluate to null
.
If include_extra
is false, the "optional"
value is omitted. compact()
ensures the final list doesn't retain that null
, yielding ["core", "final"]
. This helps avoid issues in modules that do not tolerate null
values in lists.
variable "include_extra" {
default = false
}
locals {
list = compact([
"core",
var.include_extra ? "optional" : null,
"final"
])
}
output "result" {
value = local.list
}
Example 3: Using compact with flattened lists
In this example, we first flatten a list of lists using flatten()
, then pass the result to compact()
to remove any null
values. The end result is a clean, flat list: ["a", "b", "c"]
.
locals {
nested_lists = [
["a", null],
[null, "b"],
["c"]
]
flat_and_clean = compact(flatten(local.nested_lists))
}
output "flat_cleaned_list" {
value = local.flat_and_clean
}
This approach is useful when handling outputs from modules or remote data sources that return nested structures.
Example 4: Combining compact with concat for dynamic lists
Terraform concat()
function joins two lists---one static and one conditional.
If add_debug
is false
, ["debug"]
is replaced by [null]
, but compact()
ensures the merged list excludes the unwanted null
.
variable "add_debug" {
default = false
}
locals {
base = ["main", "worker"]
debug = var.add_debug ? ["debug"] : [null]
final_roles = compact(concat(local.base, local.debug))
}
output "roles" {
value = local.final_roles
}
Note: concat()
requires each argument to be a list, even a placeholder like [null]
, not just null
, or it will throw an error.
Example 5: Using compact inside a module to filter inputs
Here, the root module passes a dynamically constructed list to a child module. The list includes optional elements based on input variables. compact()
filters out null
values before they're passed to the module, ensuring services
always receives a clean list.
# root/main.tf
module "example" {
source = "./modules/service"
services = compact([
"api",
var.enable_cache ? "cache" : null,
var.enable_auth ? "auth" : null
])
}
# root/variables.tf
variable "enable_cache" {
default = true
}
variable "enable_auth" {
default = false
}
# modules/service/variables.tf
variable "services" {
type = list(string)
}
# modules/service/main.tf
output "services_used" {
value = var.services
}
Example 6: Using compact in for_each to skip unwanted elements
Terraform requires for_each
keys to be non-null and unique, so using compact()
here guarantees safe and valid iteration.
Below, we loop over a list of usernames that may include null
values. Before applying for_each
, compact()
ensures all null
entries are excluded.
variable "users" {
default = ["alice", null, "bob", null, "carol"]
}
resource "null_resource" "user_setup" {
for_each = toset(compact(var.users))
triggers = {
user = each.key
}
}
You can also use the Terraform toset()
function to remove duplicates, so if preserving duplicates or order is important, use for
loops over lists instead.
What is the difference between concat and compact in Terraform?
concat function in Terraform is used to combine multiple lists into a single list. It takes two or more list arguments and returns a new list containing all the elements in the given order.
Terraform compact()
removes all null
and empty string (""
) values from a list. However, it does not alter other types of values, and it does not concatenate lists.
For example:
concat(["a"], ["b", null]) => ["a", "b", null]
compact(["a", null, "b"]) => ["a", "b"]
You can use concat
to join lists together and compact
to clean out empty strings from a list. These functions can also be combined when you need to merge lists and remove empty entries.
Key points
The compact()
function in Terraform helps streamline your code by removing any null
or empty string values from lists, making your configurations safer, less error-prone, and easier to maintain.
We encourage you to explore how Spacelift makes it easy to work with Terraform. If you need help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run, instead of using a static pair on your local machine, Spacelift is a fantastic tool for this.
If you want to learn more about Spacelift, create a free account today or book a demo with one of our engineers.
Written by Mariusz Michalowski
Top comments (0)