Back to all blog posts
Product Update

Introducing Terramate CLI 0.9.0 - GitLab, Workspaces, and Partial Evaluation

Terramate 0.9.0 adds full support for GitLab, Terraform CLI Workspaces and Partial Evaluation.

Sören Martius
Sören Martius
· 4 min read
Introducing Terramate CLI 0.9.0 - GitLab, Workspaces, and Partial Evaluation

Another month, another Terramate release. After working hard for the past few weeks, we are finally proud to introduce Terramate CLI 0.9.0 , which includes some major improvements to streamline your Terramate experience with Terraform and OpenTofu.

Let’s dive right in.

GitLab Support

Previously, automating Terramate in GitLab CI/CD was quite cumbersome and painful. We acknowledged your feedback and are happy to announce that Terramate CLI and Terramate Cloud are now fully supported in GitLab CI/CD.

Here’s what we’ve added to streamline your experience:

  • If explicitly enabled, Terramate CLI will now collect plan files and metadata when working in GitLab repositories for Merge Requests, Deployments and scheduled drift detection workflows and sync the data to Terramate Cloud.
  • Plan previews are now available for all changed Stacks in GitLab Merge Requests.
  • We’ve added Blueprints for GitLab CI/CD pipelines to our docs allowing you to configure production-grade pipelines for previews, deployments, drift detection and reconciliation workflows in your GitLab repositories in no time!

GitLab Deployment Example

Support for Terraform CLI Workspaces

Many of you manage environments with Terramate by using one Stack per environment. While this works for most use cases, sometimes you might want to use Terraform CLI Workspaces instead, which require you to manage multiple Workspaces in the same Stack.

To support Workspaces and any other approach that enables managing different environments within the same Stack, we just added experimental support for a new feature: Deployment Targets. This allows to keep separate Stack information when the same Stacks are deployed to multiple environments, i.e., production and staging.

Since Deployment Targets are an experimental feature, it needs to be explicitly enabled in your with terramate.config.experiments = ["targets"]  and = true .

terramate {
  required_version = ">= 0.9.0"
  config {

    cloud {
      # Configure the namespace of your Terramate Cloud organization
        organization = "terramate-demo"

      # Opt in for the deployment targets feature
      targets {
        enabled = true

    # Enable experiments
    experiments = [

Once enabled, commands that synchronize or read stack information to Terramate Cloud require a -target <target_id>  parameter. These include:

  • terramate run --sync-deployment/--sync-drift-status/--sync-preview
  • terramate script run
  • terramate run --status
  • terramate list --status
  • terramate cloud drift show

The following example demonstrates pushing a Terraform CLI Workspace as a Deployment Target to Terramate Cloud.

# Create a new Terraform CLI Workspace called 'prod'
terramate run \
  -- \
  terraform workspace new prod 

# Sync the Workspace in all Stacks as a Deployment Target 'prd' to Terramate Cloud using a Drift Detection Run
terramate run \
  --sync-drift-status \
  --terraform-plan-file plan.tfplan \
  --target prod \
  -- \
  terraform plan -out plan.tfplan -detailed-exitcode

Please look at our example repository for a complete example of using Terraform CLI Workspaces with Deployment Targets.

Lets Variable Support for Scripts

Sometimes, it’s helpful to declare a variable that can be reused within the same Terramate Script to keep your workflow as DRY as possible. For that, we just added support for Lets variables to Terramate Scripts.

script "deploy" {
  description = "Run a Terraform/Tofu deployment"

  lets {
    provisioner = "terraform" # another option: "tofu"

  job {
    name        = "deploy"
    description = "Initialize, validate and deploy Terraform stacks"
    commands = [
      [let.provisioner, "init"],
      [let.provisioner, "validate"],
      ["tfsec", "."],
      [let.provisioner, "apply", "-auto-approve"],

This allows you to configure repetitive values, such as commands used in Scripts, to keep your workflows even more DRY .

Ignore Triggers

Trigger enables you to forcibly mark a stack as changed even if it doesn't contain any code changes according to Change Detection. This is particularly helpful for triggering stacks to be run when, e.g., a deployment fails on apply-after-merge workflows for Terraform and OpenTofu.

Some of our customers asked for a way to enforce exactly the inverted behavior of normal triggers. For that, we just added Ignore Triggers to Terramate CLI.

terramate experimental trigger /path/to/stack --ignore-change

This can be helpful when you make cosmetic changes to one or more stacks that don't affect the managed resources and can now be done by using the --ignore-change flag to trigger Stacks to remain unchanged. This flag configures the change detection to ignore these stacks in the next Pull Request and Deployment.

Partial Evaluation

One of Terramate's most powerful features is the native Code Generation for Terraform, OpenTofu, YAML, JSON and other common configuration languages.

However, before Terramate CLI v0.9.0, the code generation didn’t allow for partial evaluation which made it unsuitable for specific use cases such as assigning Data Sources to Globals .

To overcome this, we finally added support for [for ...]  and {for ...}  expressions containing Terramate variables and functions inside the generate_hcl.content  block.

This now finally allows you to configure more dynamic code generation configurations such as the following:

globals "terraform" "providers" "cloudflare" {
  source  = "cloudflare/cloudflare"
  version = "~> 4.29"
  enabled = true

  config = {
    some_config = true

  config_partial = {
    api_key = ""
    email   = ""

generate_hcl "" {

  lets {
    required_providers = { for k, v in tm_try(global.terraform.providers, {}) :
      k => {
        source  = v.source
        version = v.version
        } if tm_alltrue([
          tm_try(v.enabled, true),
          tm_length(tm_split(".", k)) == 1,

    providers = { for k, v in tm_try(global.terraform.providers, {}) :
      k => {config = tm_try(v.config, {}), config_partial = tm_try(v.config_partial, {})} if tm_alltrue([
        tm_length(tm_split(".", k)) == 1,
        tm_try(v.enabled, true),
        tm_can(v.config) || tm_can(v.config_partial)

  content {
    # terraform version constraints
    terraform {
      required_version = tm_try(global.terraform.version, "~> 1.8")

    # Provider version constraints
    terraform {
      tm_dynamic "required_providers" {
        attributes = let.required_providers

    # Provider configs
    tm_dynamic "provider" {
      for_each   = let.providers
      labels     = [provider.key]
      attributes = tm_merge(
        tm_try(provider.value.config, {}),
        tm_try({for k, v in provider.value.config_partial : k => tm_hcl_expression(v)}, {}),

Which will generate the following file, allowing you to bring your code generation configuration to the next level.

provider "cloudflare" {
  api_key     =
  email       =
  some_config = true

Bugfixes and Minor Improvements

Other than adding support for GitLab CI/CD, Terraform CLI Workspaces, Partial Evaluation, Ignore Triggers and Lets Variables in Scripts, we also fixed a variety of bugs and added a bunch of minor improvements. For a complete overview of all changes please take a look at the release notes.


With the 0.9.0 release of Terramate CLI, we added a bunch of great improvements requested by our community that significantly improved the Developer Experience when working with Terramate CLI and Cloud

If you don’t use Terramate yet, we recommend you take it for a spin . A feedback we frequently hear from the community is that Terramate CLI makes using Terraform (and OpenTofu) “so much simpler and easier to use”.

If you have any questions or feature requests - or if you need help, feel free to join our Discord Community .

We’d love to hear from you!

Soren is the co-founder and Chief Executive Officer at Terramate. Prior to founding Terramate, he consulted companies such as Flink, 1Komma5 and Nothing to design and implement cloud- and internal developer platforms.