When you’re working with lists in Terraform, you’ll often want just a portion of them. For example, the first two availability zones in a region, or the middle three subnets from a larger pool. That’s exactly what slice() is for. It returns a new list that’s a contiguous sub-range of the original.
In this article we’ll explain what the Terraform slice function is and how to use it in practice.
slice is a Terraform built-in function that extracts a sublist from a list by specifying start and end indices. It is useful for manipulating subsets of data, especially when working with dynamically generated lists or when only part of a list needs to be passed to a resource or module. It mimics slicing behavior in languages like Python.
The syntax is slice(list, startindex, endindex), and it returns a new list that includes elements from startindex up to but not including endindex. The indices are zero-based, and the original list is not modified.
For example:
slice(["a", "b", "c", "d"], 1, 3)returns ["b", "c"].
Terraform will error if the startindex or endindex is outside the valid bounds of the list (e.g., endindex > length(list)).
In this example, the list local.azs contains four availability zones. The goal is to assign only the first three zones for use in subnet distribution.Â
locals {
azs = ["us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d"]
first3 = slice(local.azs, 0, 3)
}By calling slice(local.azs, 0, 3), Terraform returns the first three items: ["us-east-1a", "us-east-1b", "us-east-1c"]. The start index 0 includes the first element, while the end index 3 excludes the fourth.Â
This is particularly useful when working in regions that support more zones than you want to use, as it ensures your subnets or instances remain within a predictable set of zones.
Here, the list local.cidrs contains three subnet CIDR blocks. The intention is to reserve the first subnet (e.g., for a management network) and assign the rest to application workloads.
Using slice(local.cidrs, 1, length(local.cidrs)), the function extracts all items starting from index 1 up to the length of the list, which effectively returns [“10.0.1.0/24”, “10.0.2.0/24”].Â
However, note that using negative end indices is sometimes seen as less clear. Some prefer explicitly using length(list) – 1 for clarity.
locals {
cidrs = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
remaining = slice(local.cidrs, 1, length(local.cidrs))
}Using slice(local.cidrs, 1, length(local.cidrs)), the function extracts all items starting from index 1 up to the length of the list, which effectively returns ["10.0.1.0/24", "10.0.2.0/24"].Â
However, note that using negative end indices is sometimes seen as less clear. Some prefer explicitly using length(list) - 1 for clarity.
In this example, the local.names list includes four components of a distributed system.Â
locals {
names = ["db", "api", "cache", "worker"]
trimmed = slice(local.names, 0, -1)
}If, for instance, the last element (“worker”) is optional or needs to be deployed separately, you can exclude it by using a negative end index. slice(local.names, 0, -1) starts at the first item and stops just before the last, resulting in ["db", "api", "cache"].Â
Negative indices in Terraform are relative to the end of the list, so -1 effectively points to the last element, -2 to the second-last, and so on.Â
Imagine you want to create public subnets in only the first two availability zones of whatever region you deploy to. You don’t want to hard-code AZ names (they differ by region), and you’d like the configuration to keep working even if the cloud provider adds more AZs later.
We’ll start by asking AWS for all AZ names, then slice that list to the first two. Everything else, subnet resources, route tables, and so on, keys off the sliced list, so the plan stays deterministic and tidy.
# Assumes you have these prerequisites:
# - aws_vpc.main resource already defined
# - var.vpc_cidr variable defined (e.g., "10.0.0.0/16")
# Discover all AZs in the current region
data "aws_availability_zones" "available" {
state = "available"
}
# Choose the first two AZs, regardless of how many exist in the region
locals {
azs_selected = slice(data.aws_availability_zones.available.names, 0, 2)
}
# Example: create one public subnet per selected AZ
resource "aws_subnet" "public" {
for_each = toset(local.azs_selected)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, index(local.azs_selected, each.key))
availability_zone = each.key
tags = {
Name = "public-${each.key}"
}
}Here’s what’s happening:
- The
aws_availability_zonesdata source returns a list like["eu-central-1a", "eu-central-1b", "eu-central-1c", …] slice(..., 0, 2)reduces that to the first two entries- The
for_eachthen iterates over exactly those two values, creating two subnets cidrsubnet(...)uses the index of each AZ to carve distinct CIDR blocks
This approach is preferable to hard-coding because it avoids region-specific AZ labels, adapts automatically if AWS adds or removes availability zones, and keeps your module portable across regions without conditionals or extra variables. In other words, you write the logic once and run it everywhere.
Terraform’s slice(list, start, end) returns a sublist from start (inclusive) up to end (exclusive), supporting both positive and negative indices. The function errors if indices fall outside valid bounds, but end can safely equal length(list).Â
Use slice only for lists — for strings or conditional filtering, use other functions like substr() or for expressions.
Terraform is really powerful, but to achieve an end-to-end secure GitOps approach, you need to use a product that can run your Terraform workflows. Spacelift takes managing Terraform to the next level by giving you access to a powerful CI/CD workflow and unlocking features such as:
- Policies (based on Open Policy Agent)
- Multi-IaC workflows
- Self-service infrastructure
- Integrations with any third-party tools
If you want to learn more about Spacelift, create a free account today or book a demo with one of our engineers.
Note: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.
Manage Terraform better with Spacelift
Build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization and many more.
