terraform-wrapper 0.4.0

A type-safe Terraform CLI wrapper for Rust
Documentation

terraform-wrapper

Crates.io Documentation CI License

A type-safe Terraform CLI wrapper for Rust.

Installation

[dependencies]
terraform-wrapper = "0.3"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

Minimum supported Rust version: 1.85.0

Quick Start

use terraform_wrapper::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let tf = Terraform::builder()
        .working_dir("./infra")
        .build()?;

    // Initialize providers
    InitCommand::new().execute(&tf).await?;

    // Apply changes
    ApplyCommand::new()
        .auto_approve()
        .var("region", "us-west-2")
        .execute(&tf)
        .await?;

    // Read outputs
    let result = OutputCommand::new()
        .name("endpoint")
        .raw()
        .execute(&tf)
        .await?;

    if let OutputResult::Raw(value) = result {
        println!("Endpoint: {value}");
    }

    // Tear down
    DestroyCommand::new()
        .auto_approve()
        .execute(&tf)
        .await?;

    Ok(())
}

Note: You must import the TerraformCommand trait to call .execute(). The prelude module re-exports everything you need.

Commands

Lifecycle

Command Description
InitCommand Prepare working directory, download providers
PlanCommand Preview infrastructure changes
ApplyCommand Create or update infrastructure
DestroyCommand Destroy infrastructure

Inspection

Command Description
ValidateCommand Check configuration validity
ShowCommand Inspect current state or saved plan
OutputCommand Read output values
FmtCommand Format configuration files
GraphCommand Generate DOT dependency graph
ModulesCommand List installed modules
ProvidersCommand Manage providers (lock, mirror, schema)
TestCommand Run Terraform test files
VersionCommand Get Terraform version info

State and Workspace

Command Description
WorkspaceCommand Manage workspaces (list, show, new, select, delete)
StateCommand Advanced state management (list, show, mv, rm, pull, push, replace-provider)
ImportCommand Import existing infrastructure into state
ForceUnlockCommand Manually unlock state
GetCommand Download and update modules
RefreshCommand Update state to match remote (deprecated)

Escape Hatch

Command Description
RawCommand Run any subcommand not covered above

Streaming Output

Long-running commands like apply produce streaming JSON events. Use stream_terraform to process them in real-time:

use terraform_wrapper::prelude::*;
use terraform_wrapper::streaming::{stream_terraform, JsonLogLine};

# async fn example() -> terraform_wrapper::error::Result<()> {
# let tf = Terraform::builder().build()?;
let result = stream_terraform(
    &tf,
    ApplyCommand::new().auto_approve().json(),
    &[0],
    |line: JsonLogLine| {
        println!("[{}] {}", line.log_type, line.message);
    },
).await?;
# Ok(())
# }

See the streaming_apply example for a complete working example.

Config Builder

Define Terraform configs entirely in Rust -- no .tf files needed. Enable the config feature:

[dependencies]
terraform-wrapper = { version = "0.3", features = ["config"] }
use terraform_wrapper::config::TerraformConfig;
use serde_json::json;

# fn example() -> std::io::Result<()> {
let config = TerraformConfig::new()
    .required_provider("aws", "hashicorp/aws", "~> 5.0")
    .backend("s3", json!({ "bucket": "my-tf-state", "key": "state", "region": "us-west-2" }))
    .provider("aws", json!({ "region": "us-west-2" }))
    .variable("instance_type", json!({ "type": "string", "default": "t3.micro" }))
    .data("aws_ami", "latest", json!({ "most_recent": true, "owners": ["amazon"] }))
    .resource("aws_instance", "web", json!({
        "ami": "${data.aws_ami.latest.id}",
        "instance_type": "${var.instance_type}"
    }))
    .local("common_tags", json!({ "ManagedBy": "terraform-wrapper" }))
    .module("vpc", json!({ "source": "terraform-aws-modules/vpc/aws", "version": "~> 5.0" }))
    .output("instance_id", json!({ "value": "${aws_instance.web.id}" }));

let dir = config.write_to_tempdir()?;
// Terraform::builder().working_dir(dir.path()).build()?;
# Ok(())
# }

See the config_builder example and the TerraformConfig API docs for full details.

Features

Feature Default Description
json Yes Typed JSON output parsing via serde / serde_json
config No TerraformConfig builder for .tf.json generation

Disable defaults for raw command output only:

[dependencies]
terraform-wrapper = { version = "0.3", default-features = false }

Why terraform-wrapper?

terraform-wrapper terrars terraform-rs
Approach CLI wrapper CDK-style codegen Minimal CLI wrapper
Async Yes (tokio) No No
JSON output Typed structs N/A No
Maintained Active Active Unmaintained (2021)
Use case Orchestration tools Generate .tf in Rust Basic CLI calls

Use terraform-wrapper when you need to programmatically drive Terraform lifecycles (provision, extract outputs, tear down) from Rust with type-safe, async APIs.

Documentation

Full API reference is available on docs.rs.

See the examples/ directory for working examples:

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.