What Is Infrastructure as Code?

Infrastructure as Code (IaC) is the practice of defining and managing your infrastructure — servers, networks, databases, load balancers — using machine-readable configuration files rather than manual processes or interactive tools. Those files are stored in version control, reviewed like application code, and applied automatically through pipelines.

The shift from clicking around in a cloud console to writing declarative configuration fundamentally changes how reliably you can provision and replicate environments.

Why IaC Matters

  • Repeatability: the same configuration produces the same infrastructure every time, eliminating "works on my environment" problems at the infrastructure level
  • Auditability: every change is tracked in git — who changed what, when, and why
  • Disaster recovery: rebuild an entire environment from configuration files, not memory and runbooks
  • Collaboration: infrastructure changes go through pull requests, enabling peer review before anything is applied
  • Speed: provisioning environments that took days of manual work can be automated to run in minutes

Choosing Your IaC Tool

The right tool depends on your cloud provider, existing ecosystem, and team expertise:

ToolApproachBest For
Terraform / OpenTofuDeclarative, provider-agnosticMulti-cloud, broad ecosystem
AWS CloudFormationDeclarative, AWS-nativeAll-in on AWS
PulumiImperative (real programming languages)Teams who prefer code over DSLs
AnsibleProcedural, agentlessConfiguration management, VM provisioning
HelmDeclarative, Kubernetes-nativeKubernetes workload management

Terraform (and its open-source fork OpenTofu) is the most widely used for cloud provisioning. Ansible excels at configuration management and is commonly used alongside Terraform.

Core Concepts in Terraform

Providers

Providers are plugins that know how to talk to a specific API — AWS, GCP, Azure, Datadog, GitHub, and hundreds more. You declare which providers you need, and Terraform downloads them automatically.

Resources

Resources are the building blocks: an EC2 instance, an S3 bucket, a DNS record. You declare the desired state, and Terraform figures out what API calls are needed to achieve it.

State

Terraform maintains a state file that maps your configuration to real-world resources. This is what allows it to detect drift and calculate diffs. Store state remotely (S3 + DynamoDB for locking is the standard AWS pattern) — never commit state files to git.

Plan and Apply

The core workflow is: terraform plan to preview changes, then terraform apply to execute them. Always review the plan output before applying — especially in production.

Structuring Your IaC Repository

A common and effective structure separates environments and uses reusable modules:

  • modules/ — reusable, parameterized infrastructure components (e.g., a VPC module, an ECS service module)
  • environments/dev/ — configuration for the development environment
  • environments/staging/ — configuration for staging
  • environments/production/ — production configuration, with stricter access controls

Each environment calls the shared modules with environment-specific variables. This avoids duplicating infrastructure definitions while keeping environment differences explicit and auditable.

IaC in Your CI/CD Pipeline

IaC should be automated through your pipeline like any other code:

  1. On pull request: run terraform fmt, terraform validate, and terraform plan — post the plan output as a PR comment
  2. On merge to main: run terraform apply automatically for non-production environments
  3. For production: require manual approval of the plan before applying

Tools like Atlantis or Terraform Cloud can manage this workflow with built-in plan/apply automation and access controls.

Common Mistakes to Avoid

  • Manually editing infrastructure in the console after applying IaC — this causes state drift
  • Storing sensitive values (passwords, API keys) in configuration files — use a secrets manager
  • Not using remote state — local state files get lost and can't support team collaboration
  • Giant monolithic configurations — break infrastructure into focused, composable modules