Skip to content

Quick Start

Prepare a module

The examples on this page run against a real Terraform module directory. If you already have one, point at it directly. Otherwise, this snippet creates a minimal module that runs anywhere — it uses Terraform's built-in terraform_data resource, so it needs no cloud credentials and downloads no providers:

import os
import tempfile

module_dir = tempfile.mkdtemp()
with open(os.path.join(module_dir, "main.tf"), "w") as f:
    f.write(
        '''
        variable "environment" {
          type    = string
          default = "dev"
        }

        resource "terraform_data" "example" {
          input = var.environment
        }

        output "environment" {
          value = terraform_data.example.output
        }
        '''
    )

Every example below uses module_dir as the working directory.

Run Terraform commands

Create a TerraformCommand for the module directory, then initialize and validate it:

from libterraform import TerraformCommand

cli = TerraformCommand(module_dir)

cli.init(check=True)
validation = cli.validate(check=True)

print(validation.value["valid"])  # True

check=True raises TerraformCommandError when Terraform reports failure, so errors surface immediately instead of hiding in a return code.

Generate a plan. Methods that support JSON output return parsed Python values, so plan.value is a list of Terraform's log events:

plan = cli.plan(check=True)

for event in plan.value:
    print(event.get("@level"), event.get("@message"))

Apply the plan. auto_approve skips the interactive prompt and input=False disables interactive input, which is what most automation wants:

apply = cli.apply(auto_approve=True, input=False, check=True)
print(apply.retcode)  # 0

Pass json=False to keep Terraform's plain text output instead of parsed JSON:

version = cli.version(json=False)
print(version.value)

Pass Terraform options

Python keyword arguments become Terraform CLI flags. Underscores become hyphens, so detailed_exitcode maps to -detailed-exitcode:

plan = cli.plan(
    detailed_exitcode=True,
    vars={"environment": "prod"},
)

The conversion rules cover the common flag shapes:

  • True / False become Terraform's lowercase booleans, e.g. lock=False is -lock=false.
  • A dict expands to repeated key=value flags, e.g. vars={"a": "1", "b": "2"} is -var=a=1 -var=b=2.
  • A list expands to a repeated flag, e.g. var_files=["a.tfvars", "b.tfvars"].

Parse Terraform configuration

TerraformConfig returns Terraform's own parsed view of a configuration directory, without running a command:

from libterraform import TerraformConfig

module, diagnostics = TerraformConfig.load_config_dir(module_dir)

print(list(module["ManagedResources"]))  # ['terraform_data.example']
print(diagnostics)

Use asyncio

AsyncTerraformCommand lets an asyncio application await Terraform operations without blocking the event loop:

from libterraform import AsyncTerraformCommand

cli = AsyncTerraformCommand(module_dir)
validation = await cli.validate(check=True)

By default the Terraform call runs in a worker process, so Terraform's process-wide state does not leak into the event-loop process. Use backend="thread" only when you explicitly want the current-process backend. Cancelling the coroutine interrupts the worker process for the default backend.

To reuse worker processes or run Terraform commands at the same time — across modules, with sync or async APIs — see Parallel Execution, which covers TerraformPool.

See the API Reference for the generated interface documentation.