Stackvora.tech

Terraform: state, modules & workspaces

How Terraform state, modules and workspaces really work — and the patterns that scale to a real team.

Terraform's three killer features — state, modules, workspaces — are also its three biggest sources of foot-guns. Here is how to use each one in production without breaking your Friday afternoon.

State

State is Terraform's memory of what it created. It maps your .tf resources to the actual cloud IDs.

  • Always use a remote backend (S3 + DynamoDB lock, Azure Storage, GCS, Terraform Cloud). Local state = accidental drift.
  • Never edit state by hand — use terraform state mv, rm, import.
  • Version and encrypt. S3 versioning + KMS on the state bucket is non-negotiable.
terraform {
  backend "s3" {
    bucket         = "acme-tfstate-prod"
    key            = "networking/terraform.tfstate"
    region         = "eu-west-1"
    dynamodb_table = "tf-locks"
    encrypt        = true
  }
}

Modules

A module is a folder with .tf files, inputs (variables) and outputs. Two rules that keep them sane:

  1. Small and single-purpose. One module = one logical unit (a VPC, an EKS cluster, a VM). Not "everything for team X".
  2. Version them. Publish to a private registry or pin by git tag: source = "git::ssh://.../modules//vpc?ref=v1.4.2".

Workspaces (the honest truth)

Workspaces are Terraform's way to keep multiple state files under one config. They work, but:

  • Good for ephemeral environments — PR previews, temporary sandboxes.
  • Bad for prod vs staging — those should be separate configurations with different backends. Same-config divergence bites eventually.

State-file per environment (recommended)

envs/
  prod/main.tf   → backend key = prod/networking.tfstate
  staging/main.tf → backend key = staging/networking.tfstate

When to split state

A rough rule: if terraform plan takes more than 60 seconds or your team is stepping on each other's locks, split the config along a stable boundary (networking / platform / apps).

Terraform gets hard at scale not because HCL is complex — it's because state is a shared resource. Treat it like your database, not like your code.

Back to the knowledge base · Ask the AI assistant