Infrastructure as Code (IaC) Explained

Infrastructure as Code (IaC) is the practice of defining and managing cloud infrastructure servers, networks, databases, load balancers, and every other resource through machine-readable code files rather than manual processes. Instead of clicking through a cloud provider's web console to create a server, you write a configuration file that describes the server you want, run a command, and the tool creates it for you.

That shift from manual to code-based infrastructure management is one of the most important practices in modern DevOps. It transforms infrastructure from something fragile and undocumented into something version-controlled, reproducible, and reviewable just like application code.

Why code instead of clicking

Before IaC, creating infrastructure meant logging into a web console (the AWS Management Console, Azure Portal, or GCP Console) and manually clicking through forms. Create a VPC. Add subnets. Configure security groups. Launch an EC2 instance. Attach a load balancer. Set up a database.

This approach has serious problems:

No record of what you did. If someone asks "how is production configured?", the answer is "go look at the console." There is no file that describes the full environment. No history of changes. No way to know who changed what or when.

No reproducibility. Need an identical staging environment? Click through the same 47 steps again and hope you don't miss one. Need to recreate the environment after a disaster? Hope someone documented the steps and that the documentation is current.

No review process. When a developer changes application code, the team reviews it in a pull request. When someone changes infrastructure through the console, there is no review. No approval. No second pair of eyes.

No version control. Application code lives in Git with a full history of every change. Console changes vanish the moment they are made. Rolling back means manually undoing steps if you can even remember what changed.

Human error at scale. Manually configuring one server is tedious but manageable. Manually configuring fifty servers across three environments is where mistakes become inevitable.

IaC solves every one of these problems. Your infrastructure is defined in files. Those files live in Git. Changes go through pull requests. Environments are reproducible. Rollbacks are a git revert away.

Declarative vs imperative approaches

IaC tools fall into two categories based on how you describe your infrastructure.

Declarative (what you want)

With declarative IaC, you describe the desired end state. "I want two servers, a load balancer, and a database with these specific configurations." The tool examines the current state of your infrastructure, compares it to the desired state, and makes whatever changes are necessary to close the gap.

Terraform, CloudFormation, and Pulumi all use this approach. If you say "I want three servers" and two already exist, the tool creates one more. If four exist, the tool removes one. You describe the destination, not the journey.

This is the preferred approach for most infrastructure management. It is easier to reason about, handles ordering automatically, and the tool manages the complexity of determining what needs to change.

Imperative (how to get there)

With imperative IaC, you describe the specific steps to execute. "Create a server. Install Nginx. Configure the firewall. Copy the application files." The tool follows your instructions in order.

Ansible and shell scripts use this approach. You have fine-grained control over every step, which is useful for configuration management tasks installing software, modifying files, restarting services.

In practice, most teams use a combination. Terraform (declarative) to provision the infrastructure. Ansible (imperative) to configure the software running on that infrastructure.

The major IaC tools

Terraform

Terraform is the most widely used IaC tool, appearing in roughly 67% of IaC job postings. It uses a declarative language called HCL (HashiCorp Configuration Language) and supports every major cloud provider plus hundreds of other services.

Here is a simple example that creates an AWS EC2 instance:

provider "aws" {
  region = "eu-west-1"
}

resource "aws_instance" "web_server" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = "my-web-server"
  }
}

Three commands do the rest: terraform init downloads the AWS provider, terraform plan shows what will be created, and terraform apply creates the server. Change the file and run apply again to update it. Run terraform destroy to tear it all down.

Terraform's strength is multi-cloud support. The same language and workflow works whether you are creating resources on AWS, Azure, GCP, Cloudflare, Datadog, or any other supported provider.

Pulumi

Pulumi takes a different approach: instead of a custom configuration language, you write infrastructure using real programming languages Python, TypeScript, Go, or C#. This appeals to developers who prefer writing familiar code over learning HCL.

import pulumi_aws as aws

server = aws.ec2.Instance("web-server",
    ami="ami-0c55b159cbfafe1f0",
    instance_type="t3.micro",
    tags={"Name": "my-web-server"}
)

Pulumi is growing fast, particularly in teams with strong software engineering backgrounds. It supports loops, conditionals, and abstractions that are native to programming languages rather than bolted onto a configuration language.

AWS CloudFormation

CloudFormation is AWS's native IaC tool. It uses JSON or YAML templates to define AWS resources. The advantage is deep integration with AWS services new AWS features often appear in CloudFormation before third-party tools support them. The limitation is that it only works with AWS. If you need multi-cloud support, CloudFormation is not an option.

Ansible

Ansible sits between IaC and configuration management. It uses YAML playbooks to define tasks that run on servers installing packages, editing configuration files, restarting services. Unlike Terraform, which provisions infrastructure, Ansible configures what runs on that infrastructure. For a detailed comparison, see Ansible vs Terraform.

Benefits for teams

IaC transforms how infrastructure teams operate:

Speed. Creating a complete environment VPC, subnets, security groups, servers, databases, load balancers takes minutes with IaC. Manually, the same task takes hours or days.

Consistency. Every environment is created from the same code. Development, staging, and production are identical because they are built from identical files. No more "it works in staging but not production" caused by configuration drift.

Documentation that stays current. The code is the documentation. It always reflects the actual state of the infrastructure. Traditional documentation goes stale the moment someone makes a change without updating the wiki.

Collaboration through pull requests. Infrastructure changes go through the same review process as application code. A team member proposes a change, others review it, and it merges after approval. This catches mistakes before they reach production.

Disaster recovery. If an entire environment is destroyed, you recreate it by running the IaC code. No scrambling to remember how things were configured. No manual rebuilding. The code describes everything.

Cost visibility. Tools like Infracost analyse Terraform code and estimate the monthly cost before you apply changes. You can catch expensive mistakes in the pull request, not in the billing dashboard.

How IaC fits in the DevOps workflow

Infrastructure as Code does not exist in isolation. It connects to every stage of the DevOps toolchain:

Version control (Git) stores the infrastructure code alongside application code. Changes are tracked, reviewed, and auditable.

CI/CD pipelines automate the IaC workflow. When a developer merges a Terraform change, the pipeline runs terraform plan to preview the change and terraform apply to execute it. No manual command-line work.

Containers (Docker) run on the infrastructure that IaC provisions. Terraform creates the servers and networking. Docker packages the applications that run on them.

Kubernetes orchestrates containers on infrastructure that Terraform provisions. A common pattern: Terraform creates an EKS cluster, and Kubernetes manages the workloads running on it.

Monitoring (Prometheus, Grafana) observes the infrastructure that IaC creates. Terraform can provision monitoring infrastructure alongside application infrastructure, ensuring every environment includes proper observability from the start.

The typical workflow: a developer pushes a Terraform change, the CI/CD pipeline runs plan and posts the output to the pull request, a team member reviews and approves, the pipeline runs apply, and monitoring confirms the change is healthy. This entire cycle can complete in minutes.

For teams learning DevOps, IaC is a non-negotiable skill. It appears in the vast majority of job descriptions and is central to how modern infrastructure operates. If you are just starting, Terraform for Beginners walks through your first project step by step.

Frequently Asked Questions