This site uses cookies for authentication, security, and preferences. Privacy Policy

Snap CD vs Terragrunt

Terragrunt is one of the most popular tools in the Terraform ecosystem. It solves real problems — repetitive backend configuration, duplicated provider blocks, and the lack of a built-in way to orchestrate multiple Terraform root modules. If you've used Terragrunt, you've probably appreciated how much boilerplate it eliminates.

Snap CD solves a different (overlapping) set of problems: persistent orchestration, cross-state dependency management, approval workflows, and granular access control. This guide compares the two so you can decide which fits your situation — or whether you might use elements of both.

What Terragrunt is

Terragrunt is an open-source CLI tool by Gruntwork that wraps the terraform binary. It adds:

  • DRY configuration — shared backend config, provider blocks, and common variables via include and generate blocks in terragrunt.hcl files.
  • Dependency orchestrationdependency blocks that read outputs from other modules' state files, plus run-all to execute an entire dependency graph in one command.
  • Scaffold and catalog — templates for creating new modules from a standard layout.

It's a thin wrapper: your Terraform code stays standard, and Terragrunt generates the glue (backend blocks, .auto.tfvars files) before calling terraform underneath.

Architecture

This is the fundamental difference.

Terragrunt is a local CLI tool. It runs on the machine where you invoke it — your laptop, a CI runner, a bastion host. There's no server, no persistent state tracking, no web UI, no API. When the process exits, the orchestration is done.

Snap CD is a Server + Runner architecture. The Server (snapcd.io or self-hosted) handles configuration, dependency tracking, source monitoring, and logging. Runners are lightweight agents deployed in your infrastructure that execute the actual Terraform commands. The Server persists the full history of plans, applies, and approvals.

What this means in practice:

  • Terragrunt orchestrates one run at a time. If you want continuous deployment, you build that in CI.
  • Snap CD continuously monitors for changes and orchestrates deployments across your entire infrastructure graph, with a persistent audit trail.

Dependency management

Both tools solve the problem of wiring outputs from one Terraform root module into another. The approaches are fundamentally different.

Terragrunt

Terragrunt's dependency blocks read outputs directly from another module's state file:

# compute/terragrunt.hcl
dependency "networking" {
  config_path = "../networking"
}

inputs = {
  vpc_id             = dependency.networking.outputs.vpc_id
  private_subnet_ids = dependency.networking.outputs.private_subnet_ids
}

When you run terragrunt run-all apply, Terragrunt builds the dependency graph, applies modules in the correct order, and passes outputs between them.

This works well, but has constraints:

  • State access: the machine running Terragrunt needs read access to every module's state backend. For run-all across 20 modules spanning AWS, Azure, and GCP, that's a lot of credentials in one place.
  • No change detection: Terragrunt doesn't know when outputs change. You run run-all and it re-plans everything, or you manually decide which modules to touch.
  • No cascading: if networking's outputs change, Terragrunt doesn't automatically trigger a re-plan of compute. You re-run run-all and hope the dependency ordering handles it.
  • Limited dependency modelling: Terragrunt's dependency blocks are static references — there's no way to fan out dependencies with for_each or count, and cross-stack dependencies remain an open problem.
  • Local execution: the entire graph executes in one process on one machine. For large graphs, this can be slow — you're waiting for module A to finish before module B starts (unless they're independent).

Snap CD

Snap CD tracks dependencies server-side via snapcd_module_input_from_output resources:

resource "snapcd_module_input_from_output" "vpc_id" {
  module_id        = snapcd_module.compute.id
  input_kind       = "Param"
  name             = "vpc_id"
  output_module_id = snapcd_module.networking.id
  output_name      = "vpc_id"
}

The Server knows the full dependency graph. When networking's outputs change after an apply, the Server automatically queues compute for re-planning. Each Runner only needs access to its own Module's state backend — not every Module's.

DRY configuration

This is Terragrunt's strongest feature, and Snap CD doesn't try to compete here.

Terragrunt eliminates repetitive Terraform boilerplate:

# root terragrunt.hcl
remote_state {
  backend = "s3"
  config = {
    bucket         = "my-terraform-state"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
    key            = "${path_relative_to_include()}/terraform.tfstate"
  }
}

generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite"
  contents  = <<EOF
provider "aws" {
  region = "us-east-1"
}
EOF
}

Every child module inherits this configuration via include. No more copying backend blocks into 30 modules.

Snap CD takes a different approach: your Terraform code is standard Terraform with its own backend configuration. If you want to reduce boilerplate in the Terraform code itself, you use Terraform's native mechanisms (shared modules, .tf files). Snap CD manages what's around the Terraform code — when to run it, what inputs to provide, who can approve it — not the code's internal structure.

If your primary pain point is Terraform boilerplate and you're a small team that doesn't need persistent orchestration, Terragrunt may be the better fit.

Execution model

Terragrunt's run-all executes the dependency graph in a single process. It parallelises independent modules (configurable with --terragrunt-parallelism) but everything runs on one machine. If the process is interrupted, you restart from the beginning — there's no checkpointing.

Snap CD distributes execution across Runners. The Server queues work, Runners pick up jobs, and results are tracked persistently. If a Runner goes down mid-apply, the Server knows where it stopped. Independent Modules execute on different Runners in parallel without sharing a machine.

For a graph of 5 modules, this distinction barely matters. For 50 modules across multiple cloud providers, it changes how you think about execution.

The run-all problem

Terragrunt's run-all has a deeper limitation: it has no internal knowledge of which modules in the selection have already been deployed and which haven't.

First-time deployments fail. When you run terragrunt run-all apply on a fresh stack, Terragrunt tries to resolve all dependency block outputs before any applies happen. If module B depends on module A's outputs and neither has been deployed, the dependency resolution fails — module A has no state yet, so there are no outputs to read. You work around this with mock_outputs, but those mocks are a maintenance burden and mask real errors. (#2714, #1246)

Plans fail on fresh stacks for the same reason. terragrunt run-all plan resolves dependency outputs upfront. On a stack where not every module has been deployed, plans for downstream modules fail because upstream outputs don't exist yet. (#2907)

Partial failures leave you in an unknown state. If run-all apply succeeds for modules A and C but fails on module B, Terragrunt has no record of what succeeded. Re-running run-all apply re-applies everything, including the modules that already succeeded. For idempotent applies this is usually fine, but it wastes time and can trigger unexpected changes if upstream state has shifted.

Partial teardowns are fragile. run-all destroy has the inverse problem: if some modules are destroyed and others fail, re-running doesn't reliably skip the already-destroyed ones. (#3183)

These aren't edge cases — they're inherent to a stateless CLI that discovers the dependency graph at invocation time and has no persistent record of deployment status. Snap CD's Server tracks which Modules have been deployed, which have pending plans, and which are waiting on dependencies, so none of these scenarios arise.

Change detection

Terragrunt has no built-in change detection. You run terragrunt run-all plan when you want to see what changed. In CI, this typically means running on every commit or on a schedule.

Snap CD monitors your Git sources continuously. When a new commit lands on the branch a Module watches, a plan is triggered automatically. When an upstream Module's outputs change, dependent Modules are re-planned. You don't need to set up CI triggers or cron jobs — the Server handles it.

Approval gates

Terragrunt has no approval mechanism. If you want approval before apply, you build it in CI — typically a manual approval step in your pipeline, or a PR-based workflow where merging triggers the apply.

Snap CD has built-in approval thresholds. You can require N approvals before a plan is applied, scoped per Module or per Stack. Approvals are tracked in the Server with a full audit trail.

Access control

Terragrunt is a CLI tool with no concept of users, roles, or permissions. Access control is handled externally — whoever can run terragrunt apply on the machine has full access to whatever that machine's credentials allow.

Snap CD has hierarchical RBAC: roles scoped to organisations, Stacks, Namespaces, Modules, and Runners. A user can be Contributor on test but Reader on prod. A service principal can have Approver on staging but nothing on production. These permissions apply uniformly across the web UI, API, and Terraform provider.

Learning curve

Terragrunt has its own configuration language — terragrunt.hcl — with include, dependency, generate, inputs, locals, and other blocks. It's HCL-based so it's familiar to Terraform users, but it's a distinct dialect with its own semantics. Teams need to learn how Terragrunt's inheritance model works, how dependency mock outputs behave, and how run-all traverses the graph.

Snap CD configuration is done either through the web UI or via the Terraform provider (standard Terraform resources). If you already know Terraform, you know how to configure Snap CD — there's no separate language to learn.

Lock-in

Both tools score well here.

Terragrunt wraps your Terraform code but doesn't modify it. Your .tf files are standard Terraform. If you remove Terragrunt, you need to add backend blocks and provider configurations back into each module, but the infrastructure code itself is unchanged.

Snap CD is similarly non-invasive. Your Terraform code has no Snap CD-specific constructs. Runners execute standard terraform plan and terraform apply. If you leave Snap CD, your Terraform code doesn't need to change — you just need another way to orchestrate it.

Comparison table

Dimension Terragrunt Snap CD
Architecture Local CLI wrapper Server + distributed runners
DRY config Strong (include, generate) Not addressed (use standard Terraform)
Dependencies dependency blocks, local state reads snapcd_module_input_from_output, server-side
Cascading Manual (run-all) Automatic on output change
Change detection None (manual/CI) Continuous source monitoring
Execution Single process, one machine Distributed across runners
Approval gates None (build in CI) Built-in with configurable thresholds
RBAC None Hierarchical, scoped to stack/namespace/module
Audit trail None (check CI logs) Persistent server-side history
Web UI None Dashboard with plan review
State access Runner needs access to all states Each runner accesses only its own module's state
Lock-in Low — standard Terraform code Low — standard Terraform code
Open source Yes (MIT) Runner is source-available; server is SaaS or self-hosted
Learning curve terragrunt.hcl dialect Terraform provider or web UI

When to choose which

Terragrunt is a good fit when:

  • You're a solo operator or small team that primarily needs DRY configuration.
  • Your dependency graph is small enough to run locally or in a single CI job.
  • You don't need persistent orchestration — running terragrunt run-all apply on demand or from CI is sufficient.
  • You want a free, open-source tool with no server infrastructure to manage.

Snap CD is a good fit when:

  • You need continuous, event-driven deployment — not just on-demand runs.
  • Your dependency graph spans multiple cloud providers or teams, and you need distributed execution.
  • You want approval gates, RBAC, and an audit trail without building them yourself.
  • You're scaling beyond what a single CI job can orchestrate.
  • You want automatic cascading: when one module's outputs change, dependents re-plan without manual intervention.

Using both? It's possible but usually unnecessary. Some teams use Terragrunt for DRY configuration within their Terraform modules and Snap CD for orchestration across Modules. But since Snap CD already handles input/output wiring, the overlap in dependency management creates confusion. Terragrunt also doesn't support injecting secrets without writing them to disk — Snap CD injects secrets as inputs and environment variables at runtime, so sensitive values never touch the filesystem. In most cases, pick one approach for dependency orchestration and stick with it.

See also

Snap CD

Intelligent GitOps for Infrastructure as Code. Automate, orchestrate, and scale your infrastructure deployments with confidence.


© 2026 Snap CD. All rights reserved.

An unhandled error has occurred. Reload 🗙