Terraform

Automating Workspace-to-Workspace Dependencies with Terraform Cloud Run Triggers

2026-04-19
NicheeLab Editorial Team

When you split infrastructure into layers — network → platform → app — across multiple workspaces, Run Triggers are what reliably re-plan and re-apply downstream when something upstream changes. You can automate the dependency entirely inside Terraform Cloud without manual operations or external CI.

Note, though, that Run Triggers are a mechanism for sequencing runs. They do not pass values. Read values via remote state and let triggers focus on kicking off runs — that role split is the core design.

Run Triggers: the big picture and use cases

A Run Trigger automatically queues a run in another workspace (within the same organization) whenever a workspace's run reaches a successful apply. You no longer need a VCS commit or UI click to keep upstream → downstream dependencies in sync — Terraform Cloud handles it end-to-end.

You can fan out from one upstream to many downstreams, and you can fan in from multiple upstreams to a single downstream. Cycles are rejected at creation time. Run Triggers themselves never carry values — outputs are read via data.terraform_remote_state. Workspaces with execution mode = local will not execute even when triggered, so remote execution is a prerequisite. Speculative plans (PR plans) and plan-only runs do not trigger downstreams.

  • Only available within a single organization
  • Successful upstream apply auto-queues the downstream
  • Does not pass data (pair with remote state)
  • Fan-out / fan-in supported, cycles forbidden
  • Downstream must be remote execution; local is unsupported
  • Speculative plans and failures do not fire triggers

Example dependency chain across workspaces

Run TriggerRun TriggerRun TriggerNetwork (A)outputs: vpcidPlatform (B)uses A outputsApp (C)uses outputs from A and B via remote state

Minimal tfe_run_trigger example (A's success triggers B)

provider "tfe" {}

# Resolve existing workspace IDs by name via a data source
data "tfe_workspace" "a" {
  name         = "network-a"
  organization = var.org
}

data "tfe_workspace" "b" {
  name         = "platform-b"
  organization = var.org
}

resource "tfe_run_trigger" "a_to_b" {
  workspace_id  = data.tfe_workspace.b.id       # downstream
  sourceable_id = data.tfe_workspace.a.id       # upstream
}

Outputs via remote state, execution via Run Triggers

The core design rule is a role split. Read outputs (vpc_id, subnet_ids, etc.) through remote state, and use Run Triggers only to auto-queue downstream runs. That setup eliminates human error and forgotten manual runs while keeping the dependency explicit in code.

When you use the remote backend within the same organization, Terraform Cloud injects a token so state is accessible without additional configuration. Sensitive outputs stay sensitive, but design your outputs to minimize exposure regardless.

  • Share values only through remote state; avoid passing them as plain variables or injecting them via external CI environment variables
  • Add validation in the downstream so it fails safely when remote state lookups fail
  • Keep Run Triggers focused on guaranteeing consistent auto-execution
  • Keep outputs minimal, name them consistently, and declare types explicitly (map / list / number / string)

Reading upstream outputs via data.terraform_remote_state

terraform {
  backend "remote" {
    organization = var.org
    workspaces {
      name = "app-c"
    }
  }
}

data "terraform_remote_state" "network" {
  backend = "remote"
  config = {
    organization = var.org
    workspaces = { name = "network-a" }
  }
}

data "terraform_remote_state" "platform" {
  backend = "remote"
  config = {
    organization = var.org
    workspaces = { name = "platform-b" }
  }
}

module "app" {
  source  = "./modules/app"
  vpc_id  = data.terraform_remote_state.network.outputs.vpc_id
  subnet_ids = data.terraform_remote_state.platform.outputs.subnet_ids
}

Setup options (UI / API / Terraform Provider) and comparison

You can create Run Triggers via the Terraform Cloud UI, the TFC/TFE API, or the Terraform Provider (tfe). For teams that prize reproducibility, the tfe provider with the tfe_run_trigger resource is the safest bet. The UI is fine for quick experiments, and the API is useful when integrating with existing automation.

Creating or modifying triggers requires at least Maintainer-equivalent permissions on the target workspace. Because the trigger is attached to the downstream workspace, double-check that you have the right permissions on the downstream side.

  • UI: Workspace → Settings → Run Triggers to link upstream/downstream
  • API: CRUD via the /workspaces/:id/run-triggers endpoint
  • IaC: declarative management with tfe_run_trigger (recommended)
MechanismAuto-triggers dependentsPasses dataPrimary use
Run TriggersQueues downstream run on successful upstream applyNo (pair with remote state)Sequencing runs across workspaces
data.terraform_remote_stateNoYes (reads outputs)Sharing values and expressing explicit dependencies
Variable SetsNoDistributes env / Terraform variablesDistributing credentials and shared variables
TFC Notifications / Run TasksControl through external integrations or policyNo (depends on design)Quality gates and external system notifications

Codifying Run Triggers with Terraform (equivalent to the UI setup)

provider "tfe" {}

variable "org" {}

resource "tfe_workspace" "a" {
  name         = "network-a"
  organization = var.org
  execution_mode = "remote"
}

resource "tfe_workspace" "b" {
  name         = "platform-b"
  organization = var.org
  execution_mode = "remote"
}

resource "tfe_run_trigger" "a_to_b" {
  workspace_id  = tfe_workspace.b.id   # downstream
  sourceable_id = tfe_workspace.a.id   # upstream
}

Run lifecycle and failure behavior

When an upstream workspace completes plan → (approval if required) → apply successfully, a run is queued on the downstream workspace. If the downstream has Auto apply disabled, the run pauses for approval after the plan. Policy violations (Sentinel / Run Tasks) or plan failures stop the chain.

When multiple upstreams trigger a single downstream, the downstream follows its workspace queue settings and runs them serially. They cannot run in parallel, but as long as your plans are idempotent that is not an issue. Cycles are blocked at creation time.

  • Trigger condition: only on a successful upstream apply
  • Plan-only, failed, or canceled runs do not fire
  • The downstream's Auto apply setting decides whether manual approval is required
  • Fan-in runs execute serially on the downstream (no parallel execution)
  • You can verify Reason = run_trigger in the UI Run details

Controlling downstream auto-apply (per-environment example)

resource "tfe_workspace" "app_dev" {
  name           = "app-dev"
  organization   = var.org
  execution_mode = "remote"
  auto_apply     = true   # dev auto-applies
}

resource "tfe_workspace" "app_prod" {
  name           = "app-prod"
  organization   = var.org
  execution_mode = "remote"
  auto_apply     = false  # prod requires approval
}

Security, permissions, and organization boundaries

Run Triggers are scoped to a single organization. Creating or modifying them requires admin-level rights on the target workspace (typically Maintainer or higher). If you need cross-org dependencies, split them at the design stage and add an alternative control plane such as notifications or approvals.

Value sharing via remote state is powerful but watch for over-exposure. Keep outputs minimal, ideally wrap them in an aggregator module, and have downstreams read only the keys they need. Take care that sensitive outputs do not leak into downstream logs or external notifications.

  • Triggers work only within the same organization (no cross-org)
  • Create permission: Maintainer / Admin equivalent on the target workspace
  • Remote state is read safely via the org token (keep outputs minimal)
  • Distribute credentials with Variable Sets, never via outputs
  • Downstream must run execution_mode = remote (local is unsupported)

Distributing shared credentials via a Variable Set (not via outputs)

resource "tfe_variable_set" "shared_creds" {
  name         = "shared-creds"
  organization = var.org
  description  = "Shared provider credentials for all envs"
}

resource "tfe_variable" "aws_access_key" {
  key             = "AWS_ACCESS_KEY_ID"
  value           = var.aws_access_key_id
  sensitive       = true
  category        = "env"
  variable_set_id = tfe_variable_set.shared_creds.id
}

resource "tfe_workspace_variable_set" "attach" {
  variable_set_id = tfe_variable_set.shared_creds.id
  workspace_id    = data.tfe_workspace.app.id
}

Exam takeaways (Authoring & Operations Pro)

Lead with the role split: Run Triggers are for auto-chaining execution, remote state is for sharing values. Run Triggers are organization-scoped, fire on successful upstream apply, queue downstream runs, do not pass data, and require remote execution downstream. Those are the high-frequency hit points.

You can configure them via UI / Provider / API, but for reproducibility tfe_run_trigger is the model answer. Earn extra credit by tying the design back to downstream Auto apply, policy checks, and serial execution under fan-in.

  • Run Triggers do not pass values → read outputs via remote state
  • Same-org only; cycles forbidden; fan-out / fan-in supported
  • Fires only on successful upstream apply (plan-only does not fire)
  • Be able to explain how downstream Auto apply interacts with policy checks
  • tfe_run_trigger is the first-choice IaC primitive

Remote backend definition (minimal exam-style example)

terraform {
  backend "remote" {
    organization = var.org
    workspaces {
      name = "platform-b"
    }
  }
}

# Explicitly expose outputs from the upstream workspace
output "subnet_ids" {
  value = module.network.subnet_ids
  sensitive = false
}

Check Your Understanding

Pro

問題 1

Within a single organization, when network-a is applied you want to automatically re-plan platform-b and app-c, and app-c needs to use outputs from both network-a and platform-b. Sensitive values must not be passed directly, and no external CI is allowed. Which design is the best fit?

  1. Configure Run Triggers network-a → platform-b, network-a → app-c, and platform-b → app-c, and have app-c read network-a and platform-b outputs via data.terraform_remote_state. Run downstream workspaces with remote execution and control app-c's Auto apply per environment.
  2. Share network-a's vpc_id with a Variable Set and rely on scheduled runs to periodically re-plan app-c.
  3. Fire a webhook via TFC notifications and have an external CI apply app-c via the CLI (cross-org is fine).
  4. Use Terraform's depends_on to express the cross-workspace dependency directly so platform-b auto-applies whenever app-c plans.

正解: A

Run Triggers for auto-chaining execution plus remote state for sharing values is the canonical role split. Run Triggers only work within a single organization, and app-c can read outputs from both network-a and platform-b. Variable Sets are too narrow for value sharing and do not auto-trigger dependents. The webhook + external CI option falls outside the constraints and assumes cross-org is OK, which it is not. depends_on cannot drive applies across workspaces.

Frequently Asked Questions

Do Run Triggers fire when the upstream apply is a no-op (no changes)?

Triggers fire on runs whose apply stage finishes successfully. Plan-only runs do not fire. Even a no-op can fire as long as the apply stage was executed and marked successful. To avoid unwanted chaining, revisit your outputs design or gate downstream runs with policies or Run Tasks.

Can Run Triggers chain across different organizations?

No. Run Triggers are scoped to a single organization. If you need cross-org orchestration, build an external pipeline that includes notifications and approvals, or add a separate control plane.

Do Run Triggers work when the downstream workspace uses execution_mode=local?

They will not execute. Run Triggers assume Terraform Cloud remote execution. Runs queued against a local-execution workspace will not be processed, so switch the workspace to remote, or use an alternative such as external CI.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Terraform

HCL Syntax: Terraform's Configuration Language (2026)

HCL2 fundamentals for Terraform — blocks, attributes, expres...

Terraform

Terraform Authoring & Operations Pro: Complete Guide (2026)

Tactics for the Terraform Pro exam — module authoring, works...

Terraform

Terraform Providers: Plugin Management Fundamentals (2026)

Provider mechanics — required_providers, versions, mirrors, ...

Terraform

Terraform Resource Blocks: Declarative Infra Units (2026)

Resource block fundamentals — addresses, references, common ...

Terraform

Terraform Data Sources: Read-Only External Data (2026)

Data source basics — declaration, refresh behavior, dependen...

Browse all Terraform articles (102)
© 2026 NicheeLab All rights reserved.