Skip to content

Infrastructure as code

Terraform builds it. Terragrunt keeps it tidy.

Every piece of AWS behind my products is code: Terraform modules for what to build, Terragrunt for where, in which account, and in what order. Here's how it's set up and why.

Terraform logo
Terraform
Terragrunt logo
Terragrunt
Terragrunt units across all environments
85
reusable Terraform modules
25
AWS accounts: shared services, dev and prod
3
root config shared by every unit
1

Why Terraform

Infrastructure you can read and review

  • The repo is the source of truth

    Nothing is clicked together in the AWS console. If it exists, it is in code, and anyone can read how it was built.

  • Every change is reviewed before it happens

    A plan shows exactly what will be created, changed or destroyed. Infrastructure changes get the same review as application code.

  • Patterns, not one-offs

    Each module does one job: a Lambda, a queue wired to a worker, a CloudFront site. A new product reuses them instead of starting from a blank page.

  • One tool for every provider

    AWS and Cloudflare live in the same codebase and the same workflow, so DNS and certificates are never a separate manual step.

Why Terragrunt on top

The same setup, 85 times, without copy-paste

  • Write the boring parts once

    One root.hcl generates the provider, version and backend files for every unit. No backend block copied into 85 folders, and no drift between them.

  • The folder decides the account

    A unit under infrastructure/production/ deploys to the production account, with the production role. The account comes from the path, not from flags someone can forget.

  • Small state, small blast radius

    Each unit has its own state file, keyed by its path in one encrypted S3 bucket with native lockfiles. A bad change to one unit cannot corrupt another.

  • Dependencies are explicit

    Units read each other’s outputs through dependency blocks: a site gets its certificate ARN and hosted zone ID from the units that created them. Nothing is hardcoded twice.

  • Secrets stay out of the repo

    Account IDs, roles and tokens come from environment variables loaded by direnv. The .hcl files are safe to share.

Dependencies

How a unit gets what it needs

A web app unit never hardcodes a certificate or a zone ID. It reads them from the units that created them.

  • Hosted zone shared-services/route-53
  • Certificate production/certificate
  • Lambda production/lambda
web-app unit production/web-app/terragrunt.hcl
cloudfront-sveltekit modules/ - shared Terraform module
Running site CloudFront, S3 assets and DNS records

What happens on apply

Resolve: Find root.hcl and work out the AWS account and role from the unit’s folder path.

The code

Small files, one shared root

A simplified, anonymised version of the real setup. Every unit is about this size.

production/web-app/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

dependency "hosted_zone" {
  config_path = "${get_repo_root()}/infrastructure/shared-services/route-53/example-zone"
}

dependency "certificate" {
  config_path = "${get_repo_root()}/infrastructure/production/certificate/example-cert"
}

dependency "lambda" {
  config_path = "${get_repo_root()}/infrastructure/production/lambda/example-web"
}

terraform {
  source = "${get_repo_root()}/modules/cloudfront-sveltekit"
}

inputs = {
  subdomain_name                 = "app.example.com"
  hosted_zone_id                 = dependency.hosted_zone.outputs.hosted_zone_id
  cloudfront_acm_certificate_arn = dependency.certificate.outputs.certificate_arn
  lambda_function_arn            = dependency.lambda.outputs.lambda_arn
}

At a glance

Terraform alone vs with Terragrunt

Terraform alone compared with Terraform plus Terragrunt
ConcernTerraform aloneWith Terragrunt
Backend and provider configRepeated in every root moduleGenerated once from root.hcl
Choosing the AWS accountVariables or workspaces per environmentDerived from the folder path, with a role per account
StateTends to grow into a few large state filesOne small state file per unit
Passing values between stacksRemote state data sources, or hardcoded valuesdependency blocks that read another unit’s outputs
Applying in the right orderManual sequencingterragrunt run --all follows the dependency graph

This is the setup behind everything on my AWS stack, the multi-account setup that limits the blast radius, and my own products.

Questions

Terraform and Terragrunt FAQ

What is the difference between Terraform and Terragrunt?

Terraform describes infrastructure as code and creates it through providers like AWS. Terragrunt, by Gruntwork, is a thin wrapper around Terraform that orchestrates many Terraform modules: it generates shared configuration such as providers and remote state, passes outputs between modules through dependency blocks, and runs them in the right order.

Do you need Terragrunt, or is Terraform enough?

For one environment and a handful of resources, Terraform on its own is enough. Terragrunt pays off once you have several accounts or environments and many separate stacks, because otherwise the backend, provider and account configuration gets copied into every one of them and slowly drifts.

How do you manage Terraform state with Terragrunt?

One encrypted S3 bucket holds every state file, and each Terragrunt unit gets its own key based on its folder path. Locking uses S3 native lockfiles, so there is no separate DynamoDB table. The backend is configured once in root.hcl and generated for every unit.

Why use folders for environments instead of Terraform workspaces?

Each environment is a separate AWS account with its own role. Folders make that visible: the path a unit lives in decides which account it deploys to, it is obvious in code review, and development and production can hold different resources instead of being forced to mirror each other.

Can you set up Terraform and Terragrunt for my team?

Yes. I can design the module and folder structure, set up multi-account state and roles, or review an existing setup that has grown hard to change. Get in touch with a short description of where you are now.

Want infrastructure like this?

Setting up Terraform and Terragrunt from scratch, or untangling a setup that's grown hard to change. Let's talk it through.

Terraform is a trademark of HashiCorp. Terragrunt is a trademark of Gruntwork. AWS service icons are the official AWS Architecture Icons. Logos are used to identify the tools; no endorsement is implied.