Spoiler alert : si vous gérez plus de trois environnements Terraform et que votre arborescence ressemble à un donjon de Dark Souls, cet article est pour vous. On va parler de Terragrunt, le wrapper qui transforme votre chaos HCL en quelque chose de civilisé.
Le problème : Terraform à l'échelle, ça fait mal
Terraform, c'est génial. On définit son infra en code, on plan, on apply, et pouf, les ressources apparaissent. C'est un peu comme un cheat code pour l'infra. Sauf que quand on commence à gérer 10, 20 ou 50 environnements, la magie s'évapore assez vite.
La duplication de code, ce fleau silencieux
Imaginons un setup classique : dev, staging, prod. Pour chaque environnement, vous avez besoin de :
- Un
provider.tf(quasi identique partout) - Un
backend.tf(la meme structure, juste la cle qui change) - Un
variables.tf(souvent copie-colle) - Un
outputs.tf(idem)
Multipliez ça par le nombre de modules (VPC, base de données, compute, monitoring...) et vous obtenez un repo où 80 % du code est du copier-coller. Si vous avez déjà fait du Terraform sur un projet de taille moyenne, vous connaissez cette douleur.
Le backend : l'angle mort de Terraform
On ne va pas se mentir : le fait que Terraform ne supporte pas les variables dans les blocs backend est une des frustrations les plus légendaires de l'écosystème. Chaque environnement nécessite une clé S3 codée en dur. Pas de variable, pas de référence, pas de magie. Juste du copier-coller manuel et la prière que personne ne se trompe de clé.
# dev/backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "dev/terraform.tfstate" # Change manuellement pour chaque env
region = "eu-west-1"
}
}
# staging/backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "staging/terraform.tfstate" # Encore du copier-coller
region = "eu-west-1"
}
}
C'est un peu comme si dans un jeu vidéo, on vous demandait de reconfigurer votre manette à chaque niveau. Techniquement faisable, mais personne n'a envie de faire ça.
L'orchestration absente
Terraform fonctionne sur un seul répertoire à la fois. Vous avez un module VPC dont dépend votre module base de données, qui lui-même est requis par votre module applicatif ? Terraform ne sait pas gérer ça nativement. Vous finissez par écrire des scripts bash de 200 lignes ou des pipelines CI/CD dignes d'un spaghetti code.
Terragrunt : le wrapper qui change la donne
Terragrunt est un outil Open Source de Gruntwork qui se positionne comme une surcouche de Terraform (et d'OpenTofu). Son objectif : éliminer la répétition et ajouter l'orchestration que Terraform n'a jamais voulu intégrer.
Le principe DRY applique a l'infra
L'idée centrale est simple : vous définissez vos modules Terraform une seule fois dans un repo "catalog", et vos environnements ne contiennent que les valeurs spécifiques. Fini les fichiers dupliqués.
infrastructure-catalog/ # Modules reutilisables
modules/
vpc/
database/
compute/
infrastructure-live/ # Environnements
root.hcl # Config partagee (provider, backend)
dev/
env.hcl # Variables specifiques dev
vpc/
terragrunt.hcl # Reference au module catalog
database/
terragrunt.hcl
staging/
env.hcl
vpc/
terragrunt.hcl
database/
terragrunt.hcl
prod/
env.hcl
vpc/
terragrunt.hcl
database/
terragrunt.hcl
Le root.hcl centralise tout ce qui est commun :
# root.hcl
remote_state {
backend = "s3"
generate = {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
}
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "eu-west-1"
}
}
La fonction path_relative_to_include() génère automatiquement une clé unique basée sur le chemin du répertoire. Plus de copier-coller, plus d'erreur humaine. C'est élégant et ça fonctionne.
Heritage hierarchique : la killer feature
Chaque fichier terragrunt.hcl enfant herite automatiquement de la configuration parente via le bloc include :
# dev/vpc/terragrunt.hcl
include "root" {
path = find_in_parent_folders("root.hcl")
}
terraform {
source = "git::git@github.com:company/infra-catalog.git//modules/vpc?ref=v1.2.0"
}
inputs = {
environment = "dev"
cidr_block = "10.0.0.0/16"
}
Quelques lignes au lieu de dizaines de fichiers dupliqués. On passe d'un repo de 20 000 lignes à environ 2 000 lignes pour la même infrastructure. Ce n'est pas une exagération : c'est un ratio documenté par des équipes qui ont fait la migration.
Gestion des dependances
C'est la ou Terragrunt brille vraiment. Les blocs dependency definissent l'ordre de deploiement :
# dev/database/terragrunt.hcl
dependency "vpc" {
config_path = "../vpc"
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id
subnet_ids = dependency.vpc.outputs.private_subnet_ids
}
Une seule commande pour tout déployer dans le bon ordre :
terragrunt run --all apply
Terragrunt analyse le graphe de dépendances et exécute les modules dans le bon ordre. Pour détruire, il fait l'inverse automatiquement. C'est un peu comme avoir un chef d'orchestre qui connaît la partition par cœur.
Terragrunt vs les alternatives
Et Pulumi dans tout ca ?
Pulumi prend une approche radicalement différente : écrire son infra dans un vrai langage de programmation (Python, TypeScript, Go). C'est puissant, mais ça implique de changer complètement de paradigme. Terragrunt, lui, reste dans l'écosystème HCL. Si votre équipe maîtrise déjà Terraform, la courbe d'apprentissage est quasi nulle.
Terraform seul avec les workspaces ?
Les workspaces Terraform sont souvent présentés comme la solution native au multi-environnement. En pratique, ils partagent la même configuration et ne gèrent pas les différences structurelles entre environnements. Si votre prod a un WAF et pas votre dev, les workspaces deviennent un nid de conditionnelles. Terragrunt résout ce problème structurellement.
Et la combinaison avec Ansible ?
Dans un workflow complet, Terraform/Terragrunt gère le provisionnement (créer les VMs, les réseaux, les buckets) tandis qu'Ansible gère la configuration des machines une fois créées. Les deux sont complémentaires. Terragrunt ne remplace pas Ansible, il structure mieux la partie Terraform du pipeline. Si vous utilisez déjà des rôles Ansible Galaxy, cette séparation des responsabilités vous parlera.
Fonctionnalites avancees
Les Stacks : reutiliser des patterns entiers
La fonctionnalité Stacks de Terragrunt permet de packager des patterns d'infrastructure complets. Au lieu de partager des modules individuels, vous partagez un "microservice pattern" qui inclut le load balancer, la base de données, le monitoring et les alertes. C'est la réutilisation à un niveau supérieur.
Hooks before/after
Terragrunt supporte des hooks qui s'executent avant ou apres les commandes Terraform :
terraform {
before_hook "validate" {
commands = ["apply", "plan"]
execute = ["tflint", "--config=.tflint.hcl"]
}
after_hook "notify" {
commands = ["apply"]
execute = ["slack-notify", "--channel=infra", "--message=Deploy done"]
}
}
Pratique pour integrer du linting, de la validation de politique ou des notifications sans scripts externes.
Compatibilite OpenTofu
Depuis le fork OpenTofu de Terraform, Terragrunt supporte les deux. Vous pouvez migrer progressivement sans changer votre structure Terragrunt. En 2026, Terragrunt est teste en continu contre OpenTofu 1.11 et Terraform 1.14 dans la CI officielle.
Quand adopter Terragrunt ?
Terragrunt n'est pas toujours necessaire. Pour un projet avec un seul environnement et quelques ressources, Terraform seul suffit largement. Voici les signaux qui indiquent qu'il est temps de passer a Terragrunt :
- Plus de 3 environnements avec des configurations similaires
- Duplication visible : vous copiez-collez des blocs
backendetprovider - Dependances entre modules que vous gerez avec des scripts maison
- Equipe grandissante qui a besoin de conventions et de structure
- Multi-compte cloud ou chaque compte a sa propre configuration
Si vous vous retrouvez a maintenir un outil de gestion de configuration maison pour orchestrer vos runs Terraform, c'est probablement le signal le plus clair.
Mise en place concrete
1. Installation
# macOS
brew install terragrunt
# Linux
curl -L https://github.com/gruntwork-io/terragrunt/releases/latest/download/terragrunt_linux_amd64 -o terragrunt
chmod +x terragrunt && sudo mv terragrunt /usr/local/bin/
2. Structure initiale
Commencez par un root.hcl qui centralise le backend et le provider, puis convertissez un environnement a la fois. La migration progressive est la cle : pas besoin de tout refactorer d'un coup.
3. Integration CI/CD
Terragrunt s'integre naturellement dans les pipelines existants. Remplacez vos terraform plan par terragrunt plan et vos terraform apply par terragrunt apply. Pour un deploiement complet, terragrunt run --all apply dans votre pipeline fait le travail.
Chez SHPV, nous accompagnons nos clients dans la structuration de leur infrastructure as code, que ce soit avec Terraform, Terragrunt ou d'autres outils de l'ecosysteme DevOps. Gerer des dizaines d'environnements proprement, c'est notre quotidien.
Conclusion
Terragrunt ne reinvente pas la roue. Il prend Terraform, qui est deja un excellent outil, et lui ajoute ce qui lui manque cruellement a l'echelle : le DRY, l'orchestration et la gestion intelligente du state. Si vous passez plus de temps a copier-coller des blocs HCL qu'a reflechir a votre architecture, il est temps d'essayer.
Spoiler alert : une fois que vous aurez goute au run --all apply, vous ne reviendrez pas en arriere.
Sources
- Keep your OpenTofu/Terraform code DRY : documentation officielle Terragrunt
- Why I Use Terragrunt Over Terraform/OpenTofu in 2025 : retour d'experience detaille sur la migration
- Terragrunt: how to keep your Terraform code DRY and maintainable : blog officiel Gruntwork


