---
title: "Infrastructure as Code with Terraform: from clicking in consoles to managing infra as code"
description: "Learn what Infrastructure as Code is, why Terraform is the leading tool and how its workflow works with providers, modules, state and CI/CD. By the Devlights CloudOps team."
url: "https://www.devlights.com/blog/terraform-infrastructure-as-code"
language: en
published: 2026-10-23T13:00:00.000Z
updated: 2026-10-28T22:29:56.367Z
type: devtalk
authors: ["Horacio Zini"]
category: "DevTalks"
tags: ["Terraform", "Infrastructure as Code", "IaC", "CloudOps", "DevOps", "AWS", "HCL", "Cloud", "CI/CD", "HashiCorp"]
---

# Infrastructure as Code with Terraform: from clicking in consoles to managing infra as code

> Infrastructure as Code is the practice of managing cloud infrastructure with declarative code instead of manual interfaces. Terraform is the leading tool: cloud-agnostic, with a huge ecosystem and a predictable, version-controlled workflow.

[YouTube](https://www.youtube.com/watch?v=0DDfpg9hsrQ)

> **TL;DR**
>
> Infrastructure as Code (IaC) is the practice of provisioning and managing cloud infrastructure through declarative code instead of manual interfaces. Terraform is the leading tool in the space: cloud-agnostic, with a huge ecosystem and a predictable, version-controlled workflow. If your team still manages infrastructure by clicking around in consoles, this is for you.

## From clicks to code: why the jump matters

When teams start working with the cloud, the natural path is the web console. It's visual, immediate and requires no prior knowledge. It works well for exploring, for learning, for a one-off resource.

The problem comes when that same approach scales: multiple environments, multiple regions, multiple services that depend on each other. In that context, the console becomes a bottleneck. Changes are manual, hard to reproduce, impossible to version and prone to human error.

The industry's answer to that problem has a name: **Infrastructure as Code**.

## What is Infrastructure as Code?

IaC is the practice of **provisioning and managing infrastructure through declarative code** instead of manual processes. Rather than describing *how* to create a resource step by step, you describe *what* you want to exist, and the tool takes care of the rest.

Three properties capture the concept well:

**Predictable.** The same code always produces the same result. There's no ambiguity about what it will create or how it will be configured.

**Idempotent.** Applying the same configuration twice has the same effect as applying it once. If the resource already exists with the right configuration, it's left untouched.

**Version-controlled.** Infrastructure code lives in a repository alongside the application code. You get a change history, you can do code reviews, you can roll back.

### The alternatives before IaC

Before IaC was widely adopted, teams managed the cloud mainly through three interfaces:

**CLI**: full control and scriptable, but it requires deep knowledge and scripts are hard to maintain at scale.

**SDK**: direct integration from application code, useful for specific cases but not designed to manage entire infrastructures.

**GUI (web console)**: the most visually accessible, but manual by definition. It doesn't scale, can't be versioned and can't be automated.

Each one has its place. But for teams managing full cloud environments, none of the three is enough on its own.

## Why Terraform?

There are several IaC tools: AWS CloudFormation, Azure ARM Templates, GCP Deployment Manager, Pulumi. Terraform stands out for one core reason: it's **cloud-agnostic**.

While CloudFormation only works with AWS, ARM only with Azure and Deployment Manager only with GCP, Terraform manages resources on any provider with the same tool and the same language. AWS, Azure, GCP, Kubernetes, Datadog, GitHub: if there's an API, there's probably a Terraform provider for it.

Some context:

- Created by **HashiCorp** in **2014**, with stable v1.0 released in 2021
- An ecosystem with **thousands of providers and modules** in the Terraform Registry
- **Acquired by IBM in 2025**, which reinforces its continuity and long-term enterprise support

## HCL: the language behind Terraform

Terraform uses **HCL (HashiCorp Configuration Language)**, a declarative language designed to be human-readable and expressive without being a general-purpose programming language.

A basic example: creating an S3 bucket on AWS.

```
provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "data_lake_raw" {
  bucket = "devlights-datalake-raw"

  tags = {
    Environment = "production"
    Team        = "cloudops"
  }
}

resource "aws_s3_bucket_versioning" "raw_versioning" {
  bucket = aws_s3_bucket.data_lake_raw.id

  versioning_configuration {
    status = "Enabled"
  }
}
```

What this code does: it declares that you want an S3 bucket with that name, those tags and versioning enabled. Terraform takes care of creating it, and if it already exists with that configuration, it does nothing.

## The two pillars of the ecosystem: Providers and Modules

### Providers

Providers are **plugins written in Go** that let Terraform talk to external APIs. Without a provider, Terraform can't manage anything. Each provider exposes a set of resources and data sources you can use in your code.

```
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.0"
    }
  }
}
```

### Modules

Modules are **reusable HCL packages** that group related resources. Instead of defining an AWS VPC from scratch every time, you use (or create) a module that encapsulates all that logic and exposes it through configuration variables.

```
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"

  name = "devlights-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1b"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]
}
```

Modules are what make infrastructure reusable across projects and teams.

## State: the source of truth

One of the most important (and most misunderstood) concepts in Terraform is **state**.

The `terraform.tfstate` file is the **bridge between your HCL code and the real resources in the cloud**. It's a JSON file that records which resources Terraform manages, what their current configuration is and what their ID is in the provider.

Why it's worth understanding well:

**Remote backend.** In team projects, state should never live locally. It's stored in a remote backend (S3, Google Cloud Storage, Azure Blob) so every team member works against the same state.

```
terraform {
  backend "s3" {
    bucket         = "devlights-terraform-state"
    key            = "cloudops/pipeline/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}
```

**Locking.** To prevent two simultaneous runs from corrupting the state, Terraform can use DynamoDB (on AWS) or other mechanisms to acquire an exclusive lock before modifying it.

**Drift.** Drift is the divergence between what the state says and what actually exists in the cloud. It can happen when someone makes a manual change in the console without going through Terraform. The `terraform plan` command detects this drift and shows it as a difference to resolve.

## The lifecycle: 4 commands to govern your infrastructure

Terraform has a well-defined workflow that repeats with every infrastructure change:

```
terraform init
```

Initializes the workspace: downloads the declared providers, installs the referenced modules and configures the backend. It's the first command you run on any new project or after cloning an existing one.

```
terraform init
terraform validate
```

Validates the HCL syntax and checks the internal consistency of the configuration. It makes no calls to the provider's API. Useful to run in CI before anything else.

```
terraform validate
terraform plan
```

The most important command in the cycle. It shows **exactly what will change** before touching anything: which resources will be created, modified or destroyed, and which will stay the same.

```
terraform plan

# Example output:
# + aws_s3_bucket.data_lake_curated will be created
# ~ aws_glue_crawler.iot_raw will be updated in-place
# - aws_lambda_function.legacy_processor will be destroyed
#
# Plan: 1 to add, 1 to change, 1 to destroy.
```

Reviewing the plan before applying it is the infrastructure equivalent of a code review.

```
terraform apply
```

Executes the changes in the plan and updates the state with the result. It asks for explicit confirmation before proceeding (or you can pass `-auto-approve` in CI/CD pipelines).

```
terraform apply
terraform destroy
```

Removes every resource managed by the configuration. Useful for cleaning up temporary environments, but use it carefully in production.

## CI/CD integration

Terraform's real power is unlocked when it's integrated into a CI/CD pipeline. The typical flow:

1. A developer opens a PR with infrastructure changes.
2. The pipeline runs `terraform validate` and `terraform plan` automatically.
3. The plan output is posted as a comment on the PR for review.
4. On merge to main, the pipeline runs `terraform apply` automatically.

Tools like Atlantis, Terraform Cloud or GitHub Actions let you implement this flow with minimal configuration.

## Conclusion

Moving from "clicking around in the console" to managing infrastructure as code isn't just a technical improvement. It's a change of model that directly affects a technology team's reliability, speed and ability to scale.

Terraform in particular solves the problem well because it doesn't tie you to a single provider, has a mature ecosystem and follows a simple mental model: you declare what you want, Terraform calculates the difference with what exists and applies only what's needed.

For teams working with multiple cloud environments, like the Devlights CloudOps Team, the difference between infrastructure managed with IaC and infrastructure managed by hand is the difference between operating with confidence and constantly putting out fires.

If your team is evaluating Terraform or needs help structuring its infrastructure as code in a scalable way, at Devlights we have hands-on experience along that path. [Let's talk](https://www.devlights.com/contact).
