teriac server What gets planned

What gets planned

How teriac server finds affected projects, picks tool versions, watches extra files with teriac:watch, and handles Terragrunt dependencies and mock outputs.

teriac finds Terraform, Terragrunt and OpenTofu projects on its own and plans the ones a pull request affects. Most repos need no config at all.

Project detection

A project is planned when a PR changes:

  • the project's own files;
  • modules it uses, and the modules those use;
  • Terragrunt includes (such as _envcommon), dependency units, read_terragrunt_config(...), file(...), and hook scripts;
  • parent root.hcl, env.hcl and version pins.

Paths built with Terragrunt functions (get_repo_root(), get_terragrunt_dir(), find_in_parent_folders()) and with locals are resolved too.

Example

modules/
  network/            ← changed in this PR
envs/
  dev/main.tf         module "net" { source = "../../modules/network" }   → planned
  prod/main.tf        module "net" { source = "../../modules/network" }   → planned
  sandbox/main.tf     no reference to modules/network                     → not planned

And in a Terragrunt repo:

_envcommon/vpc.hcl    ← changed in this PR
live/
  root.hcl
  dev/vpc/terragrunt.hcl     include "envcommon" { path = ".../_envcommon/vpc.hcl" }  → planned
  prod/vpc/terragrunt.hcl    include "envcommon" { path = ".../_envcommon/vpc.hcl" }  → planned
  prod/app/terragrunt.hcl    dependency "vpc" { config_path = "../vpc" }               → planned

Tool versions

Each project is planned with the exact tool version it pins, read the same way as the CLI's auto-switch: .terraform-version, .opentofu-version, .terragrunt-version, .tool-versions, terragrunt.hcl constraints and required_version. When it pins none, teriac uses TERIAC_DEFAULT_VERSION (latest by default).

Binaries are downloaded on demand, checksum-verified, and kept on the server's volume. Warm the cache at start-up with TERIAC_PREINSTALL, for example terraform@1.9.8,tofu@1.8.5.

Naming projects yourself

Detection covers most repos. To give projects names, set workspaces or tools, or turn autoplan off for one, list them in the repo's teriac.yaml:

# teriac.yaml
projects:
  - name: prod-network
    dir: live/prod/network
    workspace: default
    engine: opentofu          # terraform | opentofu | terragrunt
    version: 1.8.5
  - name: orders
    dir: stacks/orders
    autoplan: false           # plan only on `teriac plan -p orders`
autodiscover: true            # keep finding the other projects too (default)

All keys are in the teriac.yaml reference.

Watch extra files: teriac:watch

For a file no config mentions, such as source code that a build step packages, add a watch. Globs work, a folder means everything inside it, and watches add to automatic detection; they never replace it.

In any .tf, .tofu or .hcl file:

# teriac:watch /lambda/orders/**/*.py scripts/build.sh

In Terragrunt, with its functions:

locals {
  teriac_watch = ["${get_repo_root()}/schemas/*.json"]
}

Or in the repo's teriac.yaml:

projects:
  - dir: stacks/orders
    watch: ["/lambda/orders/**"]

Paths are relative to the project folder; a leading / means the repo root.

When plans run

Event What happens
PR opened, or new commits pushed Affected projects are planned (unless autoplan: false)
Draft PR Skipped, unless the repo sets plan_drafts: true
teriac plan comment The projects you name, or every affected project
A newer commit arrives mid-run Waiting plans for the old commit are skipped
PR merged or closed Locks released, plans and checkouts deleted

Plans and applies share TERIAC_PARALLELISM slots (4 by default). One PR gets at most TERIAC_PR_PARALLELISM (one less than the total), so a big PR never blocks everyone else.

Terragrunt dependencies

teriac never applies a dependency for you, and never applies a plan built on wrong outputs.

  • Mock outputs. A unit planned with a dependency's mock_outputs (because the dependency isn't applied yet) is flagged in the PR and can't be applied, not even with --override. teriac tells you to apply the dependency first, for example teriac apply -p live/prod/vpc.
  • Re-plans. When you apply a dependency, teriac re-plans the units that depend on it with the real outputs. That's a plan only, for you to review and apply.
  • Outdated plans. A plan made before one of its dependencies was applied is refused with "re-plan first".
  • Order. Several units applied in one command go in dependency order, and independent ones run in parallel.

Example

teriac plan                       # vpc and app are planned; app uses vpc's mock_outputs
teriac apply -p live/prod/app     # refused: app was planned with mock outputs
teriac apply -p live/prod/vpc     # applies vpc; teriac re-plans app with the real outputs
teriac apply -p live/prod/app     # applies app once you've reviewed the new plan

The run environment

Plans and applies run with your server's environment (so cloud credentials just work), minus every TERIAC_* variable, plus:

Variable Value
TF_IN_AUTOMATION, TF_INPUT=0 Non-interactive Terraform
TG_NON_INTERACTIVE, TG_NO_COLOR Non-interactive Terragrunt
CHECKPOINT_DISABLE=1 No HashiCorp update checks
TF_PLUGIN_CACHE_DIR A provider cache shared by all runs
TERIAC_REPO, TERIAC_PR_NUMBER, TERIAC_HEAD_SHA The PR being planned
TERIAC_PROJECT, TERIAC_WORKSPACE The project being planned
TERIAC_USER Who started the run
TERIAC_BRANCH The branch (drift checks)

Use them in hooks or scripts, for example to tag resources with the PR that created them. Each run times out after TERIAC_RUN_TIMEOUT_SECONDS (an hour by default).