Terraform Atlantis with Terragrunt: Complete Integration Guide 2025
Streamline Terraform with Atlantis & Terragrunt: step-by-step setup, best practices, CI/CD integration, security hardening and scaling tips.
Atlantis automates Terraform workflows through pull requests, while Terragrunt keeps your infrastructure code DRY. Together, they create a streamlined, collaborative approach to infrastructure management that scales from small teams to large enterprises.
Why combine Atlantis with Terragrunt
The integration of Atlantis and Terragrunt delivers substantial benefits for infrastructure automation while introducing some technical challenges that require careful consideration.
Key benefits drive adoption across organizations
Enhanced workflow automation transforms how teams collaborate on infrastructure changes. With pull request-based workflows, infrastructure modifications become visible, reviewable, and auditable. Custom Terragrunt workflows in Atlantis adapt to specific team processes, while pre-workflow hooks enable validation and compliance checks before executing changes.
True DRY implementation extends beyond code to your CI/CD process. Terragrunt's centralized configuration patterns allow teams to define remote backend configuration, provider settings, and common variables once, then reuse them across modules. Dependency management becomes explicit through Terragrunt dependency blocks, ensuring Atlantis understands relationships between modules.
Advanced automation capabilities make complex infrastructures manageable. Parallel execution runs Terragrunt plans and applies concurrently using workspaces, while dependency-aware automation ensures correct execution order. Support for Terragrunt's run-all
command allows operations across multiple modules simultaneously when properly configured.
Technical challenges require thoughtful solutions
Integration complexity demands careful configuration. Setting up Atlantis with Terragrunt requires custom workflow definitions, binary path management, and potentially complex configuration file management for large monorepos.
Performance considerations emerge at scale. Atlantis operates in a single-threaded manner by default, which becomes a bottleneck for large infrastructures. Parallel execution increases resource consumption as each workspace requires its own repository clone.
Security implications require attention to credential management, command injection risks, and proper state file security. Both tools need access to cloud provider credentials, making secure secret management essential.
Setting up Atlantis for Terragrunt projects
Creating a proper foundation for Atlantis with Terragrunt requires careful server setup and project structure planning.
Server installation and configuration
The default Atlantis image doesn't include Terragrunt, so you'll need to create a custom Docker image:
FROM ghcr.io/runatlantis/atlantis:latest
# Install Terragrunt
ARG TERRAGRUNT_VERSION=v0.55.0
RUN curl -Lo /usr/local/bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/${TERRAGRUNT_VERSION}/terragrunt_linux_amd64" && \
chmod +x /usr/local/bin/terragrunt
Configure your Atlantis server with appropriate flags:
atlantis server \
--repo-allowlist="github.com/your-org/*" \
--atlantis-url="https://your-atlantis-server.com" \
--gh-user="your-github-user" \
--gh-token="your-github-token" \
--gh-webhook-secret="your-webhook-secret" \
--repo-config="repos.yaml" \
--autoplan-file-list="**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl"
Terragrunt-Atlantis-Config setup
The terragrunt-atlantis-config
tool automatically generates atlantis.yaml
configurations based on Terragrunt dependency structures. This tool has become the de facto standard for managing Atlantis configuration in Terragrunt projects:
# Install terragrunt-atlantis-config
TERRAGRUNT_ATLANTIS_CONFIG_VERSION="1.20.0"
wget https://github.com/transcend-io/terragrunt-atlantis-config/releases/download/v${TERRAGRUNT_ATLANTIS_CONFIG_VERSION}/terragrunt-atlantis-config_${TERRAGRUNT_ATLANTIS_CONFIG_VERSION}_linux_amd64.tar.gz
tar xf terragrunt-atlantis-config_${TERRAGRUNT_ATLANTIS_CONFIG_VERSION}_linux_amd64.tar.gz
sudo install terragrunt-atlantis-config_${TERRAGRUNT_ATLANTIS_CONFIG_VERSION}_linux_amd64/terragrunt-atlantis-config /usr/local/bin
Add a pre-workflow hook to your server's repo configuration:
// repos.yaml
{
"repos": [
{
"id": "github.com/your-org/your-repo",
"workflow": "terragrunt",
"allowed_overrides": ["workflow"],
"allow_custom_workflows": true,
"pre_workflow_hooks": [
{
"run": "terragrunt-atlantis-config generate --output atlantis.yaml --autoplan --parallel --create-workspace",
"description": "Generate Atlantis config for Terragrunt projects"
}
]
}
]
}
Project structure recommendations
Optimal project structure for Terragrunt projects with Atlantis follows a hierarchical pattern:
.
├── terragrunt.hcl # Root configuration
├── environments
│ ├── dev
│ │ ├── terragrunt.hcl # Environment config
│ │ ├── region1
│ │ │ ├── terragrunt.hcl # Region config
│ │ │ ├── vpc
│ │ │ │ └── terragrunt.hcl # Module config
│ │ │ ├── rds
│ │ │ │ └── terragrunt.hcl
│ │ │ └── eks
│ │ │ └── terragrunt.hcl
│ │ └── region2
│ │ └── ...
│ ├── staging
│ │ └── ...
│ └── prod
│ └── ...
└── modules # Optional: Include modules
├── vpc
├── rds
└── eks
Root terragrunt.hcl
should contain common configuration like remote state and provider settings:
# terragrunt.hcl
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-west-2"
encrypt = true
dynamodb_table = "my-terraform-locks"
}
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
region = "us-west-2"
}
EOF
}
Configuring atlantis.yaml for Terragrunt
Atlantis configuration for Terragrunt projects requires special attention to workflows, dependencies, and automation.
Basic atlantis.yaml configuration
While manually creating this file is possible, using terragrunt-atlantis-config
is recommended. A basic manual configuration looks like:
version: 3
projects:
- dir: environments/dev/region1/vpc
workflow: terragrunt
- dir: environments/dev/region1/rds
workflow: terragrunt
- dir: environments/dev/region1/eks
workflow: terragrunt
# ... other projects
workflows:
terragrunt:
plan:
steps:
- env:
name: TERRAGRUNT_TFPATH
command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"'
- env:
name: TF_IN_AUTOMATION
value: 'true'
- run: terragrunt plan -input=false -no-color -out=$PLANFILE
output: strip_refreshing
apply:
steps:
- env:
name: TERRAGRUNT_TFPATH
command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"'
- env:
name: TF_IN_AUTOMATION
value: 'true'
- run: terragrunt apply $PLANFILE
Using terragrunt run-all
For multi-module operations using Terragrunt's run-all
feature:
workflows:
terragrunt-run-all:
plan:
steps:
- env:
name: TERRAGRUNT_TFPATH
command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"'
- env:
name: TF_IN_AUTOMATION
value: 'true'
- run: cd $DIR && terragrunt run-all plan -out atlantis.tfplan
apply:
steps:
- env:
name: TERRAGRUNT_TFPATH
command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"'
- env:
name: TF_IN_AUTOMATION
value: 'true'
- run: cd $DIR && terragrunt run-all apply atlantis.tfplan
Note: When using run-all
, use a relative path for the plan file instead of $PLANFILE
to ensure proper plan location and application.
Project-level autoplan configuration
Control when plans automatically run with detailed autoplan configuration:
projects:
- dir: environments/dev/region1/vpc
autoplan:
enabled: true
when_modified:
- "*.hcl"
- "*.tf*"
- "../../../modules/vpc/**/*.tf*"
workflow: terragrunt
Managing Terragrunt dependencies in Atlantis
Terragrunt's dependency blocks create relationships between modules that Atlantis must understand for proper execution.
How dependency blocks work with Atlantis
Terragrunt dependency blocks allow modules to reference outputs from other modules. When integrating with Atlantis, these dependencies require special handling because Atlantis primarily operates on individual directories.
The most effective approach uses terragrunt-atlantis-config
to generate Atlantis configuration based on Terragrunt dependency blocks:
terragrunt-atlantis-config generate --output atlantis.yaml --autoplan --parallel --create-workspace
This scans your repository, analyzes Terragrunt dependency blocks, and generates an atlantis.yaml
file that correctly maps the dependency tree to Atlantis projects.
Strategies for proper dependency resolution
Several strategies ensure proper dependency resolution in Atlantis workflows:
- Cascade dependencies: Use the
--cascade-dependencies
flag withterragrunt-atlantis-config
to ensure a module depends on direct and transitive dependencies. - Workspace isolation: The
--create-workspace
flag generates unique workspaces for each project based on their path, enabling parallel execution while maintaining dependency isolation. - Custom workflow with run-all: For complex dependency chains, configure a custom workflow using Terragrunt's
run-all
command:
workflows:
terragrunt:
plan:
steps:
- run: terragrunt run-all plan --terragrunt-non-interactive -out "$PLANFILE"
apply:
steps:
- run: terragrunt run-all apply --terragrunt-non-interactive "$PLANFILE"
- Extra dependencies: For dependencies on files not automatically detected by Terragrunt, use the
extra_atlantis_dependencies
local:
locals {
extra_atlantis_dependencies = [
"some_extra_dep",
find_in_parent_folders(".gitignore")
]
}
Handling mock outputs
When using mock outputs in dependency blocks, Atlantis may apply modules with mock values rather than actual outputs from dependencies. The run-all
command helps ensure Terragrunt applies resources in the correct dependency order:
dependency "vpc" {
config_path = "../vpc"
mock_outputs = {
vpc_id = "mock-vpc-id"
}
mock_outputs_allowed_terraform_commands = ["plan", "validate"]
}
Example atlantis.yaml for multi-account/multi-region setup
A detailed atlantis.yaml
example for a multi-account/multi-region setup demonstrates how to structure complex infrastructures:
version: 3
automerge: false
parallel_apply: true
parallel_plan: true
projects:
# Dev Account - US East Region
- name: dev_us_east_vpc
dir: dev/us-east-1/vpc
workflow: terragrunt
autoplan:
enabled: true
when_modified:
- "*.hcl"
- "*.tf*"
- "../../../common/*.hcl"
workspace: dev_us_east_vpc
- name: dev_us_east_rds
dir: dev/us-east-1/rds
workflow: terragrunt
depends_on:
- dev_us_east_vpc
autoplan:
enabled: true
when_modified:
- "*.hcl"
- "*.tf*"
- "../../../common/*.hcl"
workspace: dev_us_east_rds
# Prod Account - EU West Region
- name: prod_eu_west_vpc
dir: prod/eu-west-1/vpc
workflow: terragrunt
autoplan:
enabled: true
when_modified:
- "*.hcl"
- "*.tf*"
- "../../../common/*.hcl"
workspace: prod_eu_west_vpc
- name: prod_eu_west_rds
dir: prod/eu-west-1/rds
workflow: terragrunt
depends_on:
- prod_eu_west_vpc
autoplan:
enabled: true
when_modified:
- "*.hcl"
- "*.tf*"
- "../../../common/*.hcl"
workspace: prod_eu_west_rds
workflows:
terragrunt:
plan:
steps:
- env:
name: TERRAGRUNT_TFPATH
command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"'
- env:
name: TF_IN_AUTOMATION
value: 'true'
- run: terragrunt plan -input=false -no-color -out=$PLANFILE
apply:
steps:
- env:
name: TERRAGRUNT_TFPATH
command: 'echo "terraform${ATLANTIS_TERRAFORM_VERSION}"'
- env:
name: TF_IN_AUTOMATION
value: 'true'
- run: terragrunt apply -input=false $PLANFILE
For real-world implementations, generate this configuration automatically:
terragrunt-atlantis-config generate --output atlantis.yaml \
--autoplan --create-workspace --parallel \
--cascade-dependencies
Troubleshooting Atlantis with Terragrunt
Even with careful configuration, issues can arise when integrating these complex tools.
Configuration errors
Error: "Repo config not allowed to set 'workflow' key"
Add allowed_overrides to your server-side config:
repos:
- id: "github.com/your-org/*"
allowed_overrides: [workflow]
allowed_workflows: [terragrunt]
allow_custom_workflows: true
Error: "terragrunt: command not found"
Create a custom Atlantis Docker image with Terragrunt installed:
FROM ghcr.io/runatlantis/atlantis:v0.27.0
USER root
RUN curl -L https://github.com/gruntwork-io/terragrunt/releases/download/v${TG_VERSION}/terragrunt_linux_amd64 -o /usr/local/bin/terragrunt \
&& chmod +x /usr/local/bin/terragrunt
USER atlantis
Dependency resolution errors
Error: "Failed to parse HCL: Invalid expression..."
Use mock_outputs for dependencies that haven't been applied yet:
dependency "vpc" {
config_path = "../vpc"
mock_outputs = {
vpc_id = "mock-vpc-id"
}
mock_outputs_allowed_terraform_commands = ["plan", "validate"]
}
Performance issues
Slow plan and apply operations
Enable parallel execution with --parallel
and --create-workspace
flags:
terragrunt-atlantis-config generate --output atlantis.yaml --parallel --create-workspace
Set parallel_plan and parallel_apply in atlantis.yaml:
version: 3
automerge: false
parallel_apply: true
parallel_plan: true
Autoplan problems
Changes to HCL files don't trigger Atlantis plans
Configure the autoplan section in atlantis.yaml with correct file patterns:
autoplan:
enabled: true
when_modified:
- "*.tf"
- "*.tfvars"
- "*.hcl"
- "../*.hcl" # parent terragrunt files
Set the server-side --autoplan-file-list flag:
--autoplan-file-list="**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl"
Best practices for production implementations
Based on real-world implementations and community recommendations, follow these best practices:
- Automate configuration generation using
terragrunt-atlantis-config
with appropriate flags:
terragrunt-atlantis-config generate --output atlantis.yaml \
--autoplan --workflow terragrunt --create-workspace \
--parallel --cascade-dependencies
- Use mock outputs for initial planning to prevent dependency issues:
dependency "vpc" {
config_path = "../vpc"
mock_outputs = {
vpc_id = "mock-vpc-id"
}
mock_outputs_allowed_terraform_commands = ["plan", "validate"]
}
- Optimize dependency resolution with performance optimizations:
- Enable
--dependency-fetch-output-from-state
to fetch outputs directly from state - Use parallel execution with separate workspaces
- Consider minimizing dependency chain depth when possible
- Enable
- Maintain clearly defined boundaries:
- Organize modules by account/region/environment
- Use consistent naming conventions
- Implement custom locals to manage workflow assignments
- Leverage extra dependencies for non-Terragrunt files:
locals {
extra_atlantis_dependencies = [
"../../../modules/shared/variables.tf",
find_in_parent_folders("common_vars.yaml")
]
}
Conclusion
Integrating Terraform Atlantis with Terragrunt delivers a powerful infrastructure automation solution that enhances collaboration, enforces best practices, and maintains DRY principles. The combination's benefits—workflow automation, improved collaboration, and advanced automation capabilities—outweigh the technical challenges of integration complexity and performance considerations.
The key to success lies in proper configuration, especially around dependency management. Using tools like terragrunt-atlantis-config
to automate configuration generation makes implementing this integration significantly easier, while following established patterns for repository structure and workflow definition ensures a smooth experience.
As both tools continue to evolve, this integration represents the state of the art in infrastructure automation, enabling teams to collaborate effectively on infrastructure changes while maintaining the highest standards of consistency and reliability.