Choosing an Engine
The engine is the tool that Stategraph Orchestration runs for each plan and apply: Terraform, OpenTofu, the stategraph CLI, Terragrunt, Pulumi, CDKTF, or a custom command. The default is the Terraform CLI. Set the engine key at the top level of .stategraph/config.yml, or override it per workflow.
Built-in engines
Terraform (default)
engine:
name: terraform
version: '1.5.7'
OpenTofu
engine:
name: tofu
version: '1.9.0'
See OpenTofu.
Terragrunt
engine:
name: terragrunt
tf_version: '1.5.7'
tf_cmd selects the tool under Terragrunt (terraform by default, or tofu), and tf_version pins its version. See Terragrunt.
CDKTF
engine:
name: cdktf
tf_cmd: tofu
See CDKTF.
Pulumi
engine:
name: pulumi
The pulumi engine takes no other keys. See Pulumi.
Stategraph
engine:
name: stategraph
tf_cmd: tofu
The stategraph engine runs the stategraph CLI and keeps your state in Infrastructure as a Database, in place of a Terraform backend. The runner calls stategraph tf plan and stategraph tf apply. These commands run Terraform or OpenTofu and store the state in your Stategraph server. The engine does not collect outputs. For scoped plans, resource locks, and transactions, see Use with Orchestration.
Setting up the Stategraph engine
Prerequisites
- A Stategraph server that your runners can reach: Stategraph Cloud or a self-hosted deployment.
- An API key with permission to plan and apply the states of the repository.
- The tenant ID.
stategraph infolists your tenants. - The
stategraphCLI on a developer machine, for the one-time onboarding:
curl -sSL https://get.stategraph.com/install.sh | sh
Onboard each directory once
Each directory (with its workspace) needs a Stategraph state before its first run. On a developer machine, export STATEGRAPH_API_BASE, STATEGRAPH_API_KEY, and STATEGRAPH_TENANT_ID. Then:
- Go to the directory that holds the
*.tffiles. - If the directory has no
terraform.tfstate, create a new state:
stategraph states create --name my-app
- If a
terraform.tfstateexists, import it:
stategraph import tf --name my-app terraform.tfstate
- Both commands write
stategraph.jsonin the directory. Commit it next to the Terraform code. - Do these steps for each directory that uses this engine.
For all options, see states and import.
Enable the engine
After you commit stategraph.json in each directory, set the engine:
engine:
name: stategraph
To pin the CLI version that the runner uses, set version:
engine:
name: stategraph
version: '2.5.7'
To run OpenTofu in place of Terraform, set tf_cmd and tf_version:
engine:
name: stategraph
tf_cmd: tofu
tf_version: '1.9.0'
override_tf_cmd sets the Terraform or OpenTofu program that the CLI calls (TF_CMD), in place of terraform or tofu.
Runner secrets
The runner needs three environment variables. Set them as GitHub Actions secrets on GitHub, as masked CI/CD variables on the GitLab project, or in your self-hosted runner configuration. See Variables.
| Variable | Purpose |
|---|---|
STATEGRAPH_API_BASE |
URL of your Stategraph server, for example https://stategraph.example.com |
STATEGRAPH_API_KEY |
API key with permission to plan and apply the relevant states |
STATEGRAPH_TENANT_ID |
The tenant UUID |
All three are required. The engine's preflight fails the run if one is missing, or if the directory has no stategraph.json.
Plan and apply
- Open a pull request that changes a directory with
engine: stategraph. - Orchestration runs a plan and posts the diff on the pull request.
- Review the plan, get the required approvals, and comment
stategraph apply. - Orchestration applies against your Stategraph server. The Stategraph database records the state changes.
Custom engine
Use a custom engine for tools outside the Terraform family, for wrappers, or for legacy systems. Each key is one step, and every step is optional. Set only the steps that your workflow needs.
engine:
name: custom
# The command to run during the init step (optional)
init: ['echo', 'init']
# The command to run during the plan step (optional)
plan: ['my-custom-plan']
# The command to produce a human-readable diff of the plan output (optional)
diff: ['printf', '+ added foo\n- removed bar\n~ updated bar\n']
# The command to print the plan's resource counts as JSON (optional)
resource_summary: ['echo', '{"created": 1, "updated": 0, "replaced": 0, "deleted": 0}']
# The command to run during the apply step (optional)
apply: ['my-custom-apply']
# The command to run for stategraph apply-autoapprove, which has no stored plan (optional)
unsafe_apply: ['my-custom-apply', '--no-plan']
# The command to return output values as a JSON string (optional)
outputs: ['echo', '{"foo": "bar"}']
resource_summaryprints a JSON object with the integer keyscreated,updated,replaced, anddeleted. It runs after a plan that reports changes, and the counts appear in the summary comment.unsafe_applyruns forstategraph apply-autoapprove.- To pass data from the plan step to the apply step, write it to the path in
TERRATEAM_PLAN_FILE. The apply step can read it there.
Plan exit codes
The exit code of the plan command sets the result. 0 means that the plan succeeded and there are changes. 2 means that the plan succeeded and there are no changes. Any other exit code is a failure. Terraform and OpenTofu use the reverse with -detailed-exitcode, where 2 means changes. Wrap those tools if you pass their exit code through.
Per-workflow engines
Different workflows can use different engines, for example when environments need different tools. Put the engine block in the workflow entry:
workflows:
- tag_query: "development"
engine:
name: tofu
- tag_query: "production"
engine:
name: terraform
Best practices
- Pin versions. Use
versionon theterraformandtofuengines. Usetf_cmdandtf_versionon theterragrunt,cdktf, andstategraphengines to control which Terraform-compatible CLI runs. - Test custom engines locally with the environment variables that the runner sets, especially
TERRATEAM_PLAN_FILE.