Skip to content

About

A .NET toolkit for working with Terraform — parse HCL, load modules, inspect variables, and generate Terraform code.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

TerraformDotnet

A .NET toolkit for working with Terraform — parse HCL, load modules, inspect variables, and generate Terraform code.

NuGet License: MIT Built with GitHub Copilot

Packages

Package Description
TerraformDotnet.Hcl High-performance HCLv2 parser and writer, AOT-compatible
TerraformDotnet Terraform module loader and code generator built on top of TerraformDotnet.Hcl

Quick Start — TerraformDotnet

Load a Terraform module, inspect its variables, and generate the calling code.

Install

dotnet add package TerraformDotnet

Load and inspect a module

using TerraformDotnet.Module;

var module = TerraformModule.LoadFromDirectory("/path/to/module");

Console.WriteLine($"Required variables: {module.RequiredVariables.Count}");
foreach (var v in module.RequiredVariables)
{
    Console.WriteLine($"  {v.Name}: {v.Type?.ToHcl() ?? "any"} — {v.Description}");
}

Console.WriteLine($"Optional variables: {module.OptionalVariables.Count}");
Console.WriteLine($"Outputs: {module.Outputs.Count}");
Console.WriteLine($"Resources: {module.Resources.Count}");
Console.WriteLine($"Module calls: {module.ModuleCalls.Count}");

Generate a module call

using TerraformDotnet.Emit;

var call = new ModuleCallBuilder("my-app", module)
    .Source("git::https://example.com/modules/app?ref=v1.0")
    .FillRequired(name => $"var.{name}")
    .SetLiteral("tier", "premium")
    .IncludeOptionalComments(true)
    .Build();

var emitter = new ModuleCallEmitter(call);
string hcl = emitter.EmitModuleBlock();
// module "my-app" {
//   source = "git::https://example.com/modules/app?ref=v1.0"
//
//   project = var.project
//   region  = var.region
//   labels  = var.labels
//   tier    = "premium"
//
//   # (Optional) Maximum instance count.
//   # max_count = var.max_count
// }

Generate multiple files at once

emitter.WriteTo("output/", new FileEmitterOptions
{
    ModuleFileName = "resources-app.tf",
    VariablesFileName = "variables-app.tf",
    InputFiles = new Dictionary<string, IDictionary<string, InputValue>>
    {
        ["input-dev.tfvars"] = new Dictionary<string, InputValue>
        {
            ["project"] = new InputValue("\"dev-app\"", "Development"),
            ["region"] = "\"eu-west-1\"",
        },
        ["input-prod.tfvars"] = new Dictionary<string, InputValue>
        {
            ["project"] = new InputValue("\"prod-app\"", "Production"),
            ["region"] = "\"eu-west-1\"",
        },
    },
});

Quick Start — TerraformDotnet.Hcl

Parse and write HCL at any level of abstraction.

Install

dotnet add package TerraformDotnet.Hcl

Parse HCL into an AST

using TerraformDotnet.Hcl.Nodes;

var hcl = """
    resource "aws_instance" "web" {
      ami           = "ami-0c55b159cbfafe1f0"
      instance_type = "t2.micro"

      tags = {
        Name = "HelloWorld"
      }
    }
    """u8;

HclFile file = HclFile.Load(hcl);

HclBlock block = file.Body.Blocks[0];
Console.WriteLine(block.Type);       // "resource"
Console.WriteLine(block.Labels[0]);  // "aws_instance"
Console.WriteLine(block.Labels[1]);  // "web"

Write HCL

using TerraformDotnet.Hcl.Writer;

var buffer = new ArrayBufferWriter<byte>();
using var writer = new Utf8HclWriter(buffer);

writer.WriteBlockStart("resource", "aws_s3_bucket", "data");
writer.WriteAttribute("bucket", "my-bucket");
writer.WriteBooleanAttribute("force_destroy", true);
writer.WriteBlockEnd();
writer.Flush();

string output = Encoding.UTF8.GetString(buffer.WrittenSpan);
// resource "aws_s3_bucket" "data" {
//   bucket        = "my-bucket"
//   force_destroy = true
// }

Round-trip (parse → modify → emit)

var hcl = "name = \"old\""u8;
HclFile file = HclFile.Load(hcl);

file.Body.Attributes[0].Value = new HclLiteralExpression("new");

var buffer = new ArrayBufferWriter<byte>();
using var writer = new Utf8HclWriter(buffer);
new HclFileEmitter(writer).Emit(file);
writer.Flush();
// Output: name = "new"

Architecture

Layer Namespace Description
Reader TerraformDotnet.Hcl.Reader ref struct tokenizer — zero-copy, pull-based
Nodes TerraformDotnet.Hcl.Nodes AST model with visitor pattern and DeepClone()
Writer TerraformDotnet.Hcl.Writer Forward-only writer producing terraform fmt output
Evaluation TerraformDotnet.Hcl.Evaluation Expression evaluator with pluggable function resolver
Module TerraformDotnet.Module Terraform module loader and model
Emit TerraformDotnet.Emit Module call builder and code emitter
Functions TerraformDotnet.Evaluation Terraform function library and type conversion
Validation TerraformDotnet.Validation Variable constraint extraction and validation evaluation

See docs/hcl.md and docs/terraformdotnet.md for detailed documentation.

See docs/architecture.md for internal design and architecture.

Building

dotnet build all.csproj

Testing

dotnet test all.csproj

Performance

TerraformDotnet.Hcl uses stack-first, zero-copy design:

  • Utf8HclReader is a ref struct operating on ReadOnlySpan<byte>
  • Token values reference slices of the original input — no allocations for most tokens
  • No LINQ, no reflection in any hot path
  • AOT-compatible (IsAotCompatible = true)

License

MIT

About

A .NET toolkit for working with Terraform — parse HCL, load modules, inspect variables, and generate Terraform code.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages