Customizing the Terraform binary

When using terranix with flake-parts, the terraformWrapper option lets you control which Terraform implementation is used, bundle provider plugins, and run custom commands around each invocation. By default it uses pkgs.terraform.

All options live under terranix.terranixConfigurations.<name>.terraformWrapper.

Using OpenTofu

To use OpenTofu instead of Terraform, set the package option:

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs";
    terranix.url = "github:terranix/terranix";
    terranix.inputs.nixpkgs.follows = "nixpkgs";
    flake-parts.url = "github:hercules-ci/flake-parts";
    flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
  };

  outputs = inputs@{ flake-parts, ... }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      imports = [ inputs.terranix.flakeModules.default ];
      systems = [ "x86_64-linux" ];
      perSystem = { pkgs, ... }: {
        terranix.terranixConfigurations.default = {
          terraformWrapper.package = pkgs.opentofu;
          modules = [ ./config.nix ];
        };
      };
    };
}

This replaces every terraform call in the generated scripts (init, apply, plan, destroy) with tofu.

Bundling provider plugins

You can pre-bundle provider plugins so that terraform init doesn't need to download them:

terranix.terranixConfigurations.default = {
  terraformWrapper.package = pkgs.terraform.withPlugins (p: [
    p.aws
  ]);
  modules = [ ./config.nix ];
};

This works the same way for OpenTofu:

terraformWrapper.package = pkgs.opentofu.withPlugins (p: [
  p.aws
  p.null
  p.external
]);

Running commands before or after Terraform

The prefixText and suffixText options inject shell commands that run before and after every Terraform invocation. A common use case is exporting secrets:

terraformWrapper.prefixText = ''
  export TF_VAR_hcloud_token="$(cat /run/secrets/hcloud-token)"
'';

Or running a cleanup step afterwards:

terraformWrapper.suffixText = ''
  echo "Terraform finished, cleaning up temp files..."
  rm -f /tmp/tf-scratch-*
'';

Extra runtime inputs

When your prefixText or suffixText call external programs, add them to extraRuntimeInputs so they're available on PATH:

terraformWrapper.extraRuntimeInputs = [ pkgs.jq pkgs.awscli2 ];

For example, to fetch a secret from AWS Secrets Manager before each run:

terranix.terranixConfigurations.default = {
  terraformWrapper = {
    extraRuntimeInputs = [ pkgs.jq pkgs.awscli2 ];
    prefixText = ''
      export TF_VAR_db_password="$(
        aws secretsmanager get-secret-value \
          --secret-id my-db-password \
          --query SecretString \
          --output text
      )"
    '';
  };
  modules = [ ./config.nix ];
};