[Demo Webinar] How to Orchestrate IaC Workflows with Spacelift

➡️ Register Now

Terraform

Terraform Cidrsubnet Function Explained with Examples

terraform cidrsubnet

🚀 Level Up Your Infrastructure Skills

You focus on building. We’ll keep you updated. Get curated infrastructure insights that help you make smarter decisions.

Optimizing IP allocation in Terraform can be challenging, especially when dealing with dynamic subnetting. The cidrsubnet function helps streamline this process by programmatically dividing CIDR blocks without manual calculations. 

In this article, we dive into the practical use of the Terraform cidrsubnet function to ensure scalable, well-organized network architectures.

What we cover:

  1. What is CIDR notation?
  2. Why do you need subnetting in Terraform?
  3. What is the Terraform cidrsubnet function?
  4. How to calculate subnet addresses in Terraform
  5. Terraform cidrsubnet() vs. cidrsubnets() function
  6. How to use CIDR notation in Terraform
  7. Automating multiple subnets

What is CIDR notation?

CIDR (Classless Inter-Domain Routing) notation is a method used to represent IP addresses and their associated network prefixes. It consists of an IP address followed by a forward slash and a number indicating the subnet mask length. It is written as:

IP address/prefix length

CIDR helps efficiently allocate IP addresses and reduce routing table sizes by enabling the aggregation of multiple IP networks. It is widely used in networking, including IPv4 and IPv6, for defining network ranges in routing and firewall rules.

Here’s an example of an IP address range in CIDR notation: 192.168.1.0/24. It represents the IP range from 192.168.1.0 to 192.168.1.255. 

In IPV4, 32 bits are available, and every number corresponds to 8 bits. If you are using a /24, you define the network portion, leaving 8 bits available for the host addresses. This means that you will have 2 to the power of eight total IP addresses, which is 256 total IP addresses; only 254 will be usable (since the first is the network address and the last is the broadcast address).

Similarly, if you are using /25, you define the network portion, meaning that you will have 7 bits for the host addresses. This translates to 2 to the power of 7 total IP addresses, resulting in 128 IP addresses (126 usable for the same reasons).

This also means that when you are building host addresses, the first bits will not change (for /24, you won’t be able to change the first 24 bits).

A broader range, such as 10.0.0.0/16, covers 10.0.0.0 to 10.0.255.255, offering 65,536 addresses, is ideal for large networks. 

On the other hand, a more compact range, like 192.168.1.128/25 focuses on a smaller segment, stretching from 192.168.1.128 to 192.168.1.255, with 128 addresses, making it perfect for smaller subnet allocations.

Why do you need subnetting in Terraform?

Subnetting allows Terraform to define and manage logical subdivisions of a larger network, ensuring optimal resource allocation, which is essential for network segmentation, security, and efficient IP address management.

By subnetting, you can:

  • Enhance security by isolating different workloads (e.g., separating public-facing services from internal databases).
  • Optimize resource allocation by controlling IP address distribution and preventing exhaustion.
  • Improve network performance by reducing congestion and latency within specific segments.
  • Enable high availability by distributing resources across multiple subnets in different availability zones.
  • Follow cloud-specific best practices since AWS, Azure, and GCP require subnetting for VPCs to manage networking properly.

What is the Terraform cidrsubnet function?

The cidrsubnet function in Terraform is used to generate a subnet from an existing CIDR block. It allows you to divide a larger network range into smaller subnets by specifying a new subnet prefix length and an index to create unique subnets. This function is ideal for infrastructure automation, especially in cloud networking, where subnet segmentation is frequently required.

The syntax is as follows:

cidrsubnet(prefix, newbits, netnum)
  • prefix: The base CIDR block (e.g., "10.0.0.0/16").
  • newbits: The number of additional bits to extend the subnet mask.
  • netnum: A number used to determine the offset of the subnet based on the new bits added, affecting the calculated network address.

For example, if you have a /16 CIDR block and need multiple /24 subnets, cidrsubnet helps generate them dynamically instead of manually defining each subnet.

How to calculate subnet addresses in Terraform

Let’s consider some examples.

Example 1: Creating four /26 subnets from a /24 network

Suppose we have a /24 network (192.168.1.0/24) and we need to divide it into four /26 subnets.

variable "base_cidr" {
  default = "192.168.1.0/24"
}

output "subnet_1" {
  value = cidrsubnet(var.base_cidr, 2, 0)
}

output "subnet_2" {
  value = cidrsubnet(var.base_cidr, 2, 1)
}

output "subnet_3" {
  value = cidrsubnet(var.base_cidr, 2, 2)
}

output "subnet_4" {
  value = cidrsubnet(var.base_cidr, 2, 3)
}

Since we are adding 2 bits (newbits = 2), the new subnet mask becomes /26, effectively dividing the original /24 subnet into 2² = 4 smaller subnets. The four generated subnets will be:

  • 192.168.1.0/26
  • 192.168.1.64/26
  • 192.168.1.128/26
  • 192.168.1.192/26

Example 2: Splitting a /16 network into /20 subnets

If you start with a /16 block (10.0.0.0/16) and want to create multiple /20 subnets, you need to add 4 bits (newbits = 4).

variable "base_cidr" {
  default = "10.0.0.0/16"
}

output "subnet_1" {
  value = cidrsubnet(var.base_cidr, 4, 0)
}

output "subnet_2" {
  value = cidrsubnet(var.base_cidr, 4, 1)
}

Each /20 subnet will have 4096 IPs. The first two subnets will be:

  • 10.0.0.0/20
  • 10.0.16.0/20

Terraform automatically increments the network portion based on the netnum value.

Example 3: Allocating a /28 Subnet from a /24 Block for a Small Service

For a small private network within 192.168.100.0/24, if we want to allocate a /28 subnet for a service, we increase the mask by 4 bits (newbits = 4).

variable "base_cidr" {
  default = "192.168.100.0/24"
}

output "service_subnet" {
  value = cidrsubnet(var.base_cidr, 4, 3)
}

This calculation results in the subnet 192.168.100.48/28, which provides 14 usable IPs (since a /28 subnet has 16 total addresses, with two reserved for network and broadcast addresses).

Terraform cidrsubnet() vs. cidrsubnets() function

The cidrsubnets() function in Terraform allows you to efficiently generate multiple subnets at once by returning a tuple of subnet CIDR blocks from a single function call. It simplifies the process compared to multiple cidrsubnet() calls.

In this example, we start with a /24 network (192.168.10.0/24) and split it into three /26 subnets using cidrsubnets().

variable "base_cidr" {
  default = "192.168.10.0/24"
}

output "subnets" {
  value = cidrsubnets(var.base_cidr, 2, 2, 2)
}

The generated subnets would be:

  • 192.168.10.0/26
  • 192.168.10.64/26
  • 192.168.10.128/26

The function generates subnets in sequence based on bitwise calculations; it does not inherently prevent overlaps unless the inputs are configured correctly. Creating multiple subnets this way is more efficient and readable than using multiple cidrsubnet() calls separately.

How to use CIDR notation in Terraform

Using CIDR notation and Terraform’s cidrsubnets(), you can efficiently plan a network topology that scales over time. 

Imagine a data center with a 10.0.0.0/16 private network. The goal is to segment it into different functional subnets using CIDR notation. We’ll create separate subnets for servers, databases, and user devices, ensuring efficient IP allocation.

The base network 10.0.0.0/16 allows for 65,536 IPs. This is too large for direct usage, so we divide it into smaller blocks.

Using Terraform’s cidrsubnets() function, we can split the /16 network into three /18 subnets (each containing 16,384 IPs), assigned to different purposes.

Each /18 subnet provides a huge IP range while maintaining logical separation:

  1. 10.0.0.0/18 → Server network (Used for web and application servers)
  2. 10.0.64.0/18 → Database network (Dedicated for databases)
  3. 10.0.128.0/18 → User devices (For employees and IoT devices)

Let’s say the Server Network (10.0.0.0/18) needs further segmentation. We can divide it into four /20 subnets using:

output "server_subnets" {
  value = cidrsubnets("10.0.0.0/18", 2, 2, 2, 2)
}

This creates:

  • 10.0.0.0/20 → Web servers
  • 10.0.16.0/20 → App servers
  • 10.0.32.0/20 → API servers
  • 10.0.48.0/20 → Load balancers

Automating multiple subnets

To automate multiple subnets dynamically in Terraform, you can use the for loop with the cidrsubnet function inside a for_each or count

Suppose you have a /16 VPC CIDR (10.0.0.0/16) and want to generate five /24 subnets dynamically.

variable "vpc_cidr" {
  default = "10.0.0.0/16"
}

variable "subnet_count" {
  default = 5
}

resource "aws_subnet" "subnets" {
  count             = var.subnet_count
  vpc_id           = aws_vpc.main.id
  cidr_block       = cidrsubnet(var.vpc_cidr, 8, count.index)
  availability_zone = var.availability_zones[count.index % length(var.availability_zones)]

  tags = {
    Name = "Subnet-${count.index}"
  }
}

The cidrsubnet(var.vpc_cidr, 8, count.index) function generates /24 subnets within the /16 VPC. Since 8 additional bits convert /16 into /24, each subnet gets 256 IPs.

Using count.index % length(var.availability_zones) ensures that if there are fewer availability zones than subnets, the subnets are evenly distributed without causing an error.

If subnet_count = 5, the function creates:

  • 10.0.0.0/24
  • 10.0.1.0/24
  • 10.0.2.0/24
  • 10.0.3.0/24
  • 10.0.4.0/24

This method scales easily, reducing manual effort in managing large networks.

Key points

The Terraform cidrsubnet function helps break a parent CIDR block into smaller subnets by specifying a new subnet mask and index. It’s useful for structuring VPC networks, ensuring consistent subnet sizing, and automating IP allocation.

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.

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.

Discover better way to manage Terraform

Spacelift helps manage Terraform state, build more complex workflows, supports policy as code, programmatic configuration, context sharing, drift detection, resource visualization and many more.

Learn more

Thu, May 15, 2025 @ 11:00am EDT

The First Community-Driven
IaC Conference

Register now