> For the complete documentation index, see [llms.txt](https://docs.terrakube.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.terrakube.io/2.34.0/set-up/organizations/templates.md).

# Templates

Templates allows you to customize the job workflow inside each workspace. You can define multiple templates inside each organization. Templates are written in yaml and you can specify each step to be executed once you use this template in the workspace. Lets see an example for a basic template:

#### Example 1:

```
flow:
  - name: "Plan"
    type: "terraformPlan"
    step: 100
  - name: "Apply"
    type: "terraformApply"
    step: 200
```

#### Example 2:

```
flow:
- type: "terraformPlanDestroy"
  name: "Terraform Plan Destroy from Terraform CLI"
  step: 100
- type: "approval"
  name: "Approve Plan from Terraform CLI"
  step: 150
  team: "TERRAFORM_CLI"
- type: "terraformApply"
  name: "Terraform Apply from Terraform CLI"
  step: 200
```

An `approval` step can also carry its own `onReject` command list, run when the approving team rejects the step instead of approving it — the counterpart to the `commands`/`onFailure` hooks described for other step types in the [Terraform Execution Flow](/2.34.0/reference/executor/terraform-execution-flow.md) reference. The job itself still ends up `rejected`; `onReject` is only for side effects like a notification or cleanup script, and can't approve or resume the run.

```
flow:
- type: "terraformPlan"
  step: 100
- type: "approval"
  name: "Approve Plan"
  step: 150
  team: "TERRAFORM_ADMINS"
  onReject:
    - runtime: "BASH"
      priority: 100
      script: |
        notifyRejection.sh
```

#### Example 3:

```
flow:
  - type: "terraformDestroy"
    step: 100
  - type: "disableWorkspace"
    step: 200
```

If you notice inside the **flow** section you can define any step required, for this case only 2 steps are defined. Using the **type** property you can specify the kind of step to be performed, in the above case we are using some default types like **terraformPlan** and **terraformApply.** However the power of terrakube is that you can extend your workflow to execute additional tasks using bash or groovy code. Lets see a more advanced template:

```
flow:
  - name: "Plan"
    type: "terraformPlan"
    step: 100
    commands:
      - runtime: "GROOVY"
        priority: 100
        before: true
        script: |
          @Grapes([
            @Grab('commons-io:commons-io:2.8.0'),
            @Grab('org.apache.commons:commons-compress:1.21'),
          ])

          import org.apache.commons.io.FileUtils
          
          class TerraTagDownloader {
            def downloadTerraTag(workingDirectory, version, os, arch) {
              String terraTagFile = "terratag_${version}_${os}_${arch}.tar.gz"
              String terraTagURL = "https://github.com/env0/terratag/releases/download/v${version}/${terraTagFile}"
              println "Downloading $terraTagURL"
              FileUtils.copyURLToFile(new URL(terraTagURL), new File("${workingDirectory}/${terraTagFile}"))
            }
          } 
          new TerraTagDownloader().downloadTerraTag("$workingDirectory", "0.1.29", "darwin", "amd64")
          "TerraTag Download Compledted..."
      - runtime: "BASH"
        priority: 200
        before: true
        script: |
          cd $workingDirectory;
          tar -xvf terratag_0.1.29_darwin_amd64.tar.gz;
          chmod +x terratag;
          ./terratag -tags="{\"environment_id\": \"development\"}"
  - name: "Apply"
    type: "terraformApply"
    step: 300
  - name: "Destroy"
    type: "terraformDestroy"
    step: 400
```

The previous example is using [Terratag](https://www.terratag.io/) to add the environment\_id to all the resources in the workspace. To acomplish that, the template defines some additional commands during the **Terraform Plan,** in this case a groovy class is utilized to download the Terratag binary, and a bash script is used to execute the terratag cli to append the required tags.

Using templates you can define all the business logic you need to execute in your workspace, basically you can integrate terrakube with any external tool. For example you can use [Infracost](https://www.infracost.io/) to calculate the cost of the resources to be created in your workspace or verify some policies using [Open Policy Agent](https://www.openpolicyagent.org/).

{% hint style="warning" %}
Terrakube extensions can be stored inside a GIT repository that you can configure when starting the platform. This is an example repository that you can fork or customiza to create your custom extensions <https://github.com/terrakube-io/terrakube-extensions>
{% endhint %}

There are some tools that are very common, and you don't want repeat the same code everytime or maybe other engineer already created the code and the logic to integrate with a specific tool. For these cases, inside the template is possible to reuse some logic using [Terrakube extensions](https://github.com/terrakube-io/terrakube-extensions). Basically if someone else developed an integration with an external third party service, you don't need to implement it again, you can use the extension. Let's see how the template looks like using the [Terratag extension](https://github.com/terrakube-io/terrakube-extensions/tree/main/groovy/TerraTag):

```
flow:
  - name: "Plan"
    type: "terraformPlan"
    step: 100
    commands:
      - runtime: "GROOVY"
        priority: 100
        before: true
        script: |
          import TerraTag
          new TerraTag().loadTool(
            "$workingDirectory",
            "$bashToolsDirectory",
            "0.1.30")
          "Terratag download completed"
```

If you notice the above script is more compact as is reusing some logic. If you want to simplify and reuse some templates in your organization, please check [Import Templates](/2.34.0/set-up/organizations/templates/import-templates.md).

Using Templates you can even customize the UI for each job, see [UI templates](/2.34.0/set-up/organizations/templates/ui-templates.md) for more details.

{% hint style="info" %}
To see the complete list for terrakube extensions see the [github repo](https://github.com/terrakube-io/terrakube-extensions). This repo is always growing so its possible the tool you need is already there. In this repo you can also see more templates examples for things like approvals, variable injection and so on.
{% endhint %}

### Persistent Context

If you need to store information generated on the steps defined in your template, you can use [persistent context](/2.34.0/set-up/organizations/templates/persistent-context.md).

### Creating a Template

{% hint style="info" %}
**Manage VCS Templates** permission is required to perform this action, please check [Team Management](/2.34.0/set-up/organizations/team-management.md) for more info
{% endhint %}

<figure><img src="https://1229094460-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTN6M529qVFnas8hChf2y%2Fuploads%2Fgit-blob-48e52159a051f72b616315149dbb651b4268f5d9%2Ftemplates-list.png?alt=media" alt="Templates in an organization"><figcaption><p>Templates in an organization</p></figcaption></figure>

Once you are in the desired organization, click the **Settings** button, then in the left menu select the **Templates** option and click the **Add Template** button

You will see a list of some predefined templates than you can utilize as a quick start or if you prefer you can click the **Blank Template** to start from scratch

In the next screen you can define your template and when you are ready click the **Continue** button.

Finally, you can assign a name and description to your template and click the **Create Template** button.

Now you template is ready and you can start using it in any workspace within your organization.

{% hint style="info" %}
By default Terrakube don't create any template, so you have to define the templates in your organization based on your requirements.
{% endhint %}

<figure><img src="https://1229094460-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTN6M529qVFnas8hChf2y%2Fuploads%2Fgit-blob-640812ec771257f11c3ebb5faa7c628880e47716%2Ftemplate-new.png?alt=media" alt="Creating a template: start from a blank template or a built-in integration"><figcaption><p>Creating a template: start from a blank template or a built-in integration</p></figcaption></figure>

### Editing a Template

Click the **Edit** button next to the Template you would like to edit

Edit your template definition, description or name as desired and when you are ready click the **Save Template** button

### Deleting a Template

Click the **Delete** button next to the Template you want to delete and then click **Yes** to confirm the deletion

### Require a saved plan

{% hint style="info" %}
Supported from Terrakube 2.34.0.
{% endhint %}

Set `requireSavedPlan: true` on a `terraformApply` step to make the apply use the saved plan from the same run, instead of planning again. This guarantees that what was reviewed is what is applied.

```yaml
flow:
  - type: terraformPlan
    step: 100
  - type: approval
    step: 200
    team: TERRAKUBE_ADMIN
  - type: terraformApply
    step: 300
    requireSavedPlan: true
```

* The executor must download the saved plan, and it must be a non-empty file. If not, the step fails before running apply, even when `ignoreError` is set. Run a new job to produce and review another plan.
* The plan is applied without the current Terraform input variables. Terraform or OpenTofu validates it, including whether it is stale, and a rejected plan is not retried as a fresh apply.
* The default is `false`, which keeps today's behaviour: if the plan cannot be downloaded the executor may run a fresh apply.
* It applies only to `terraformApply` and does not add an approval step. The API and the executor, including any ephemeral executor images, must both be 2.34.0 or later.

The [GitHub Action](/2.34.0/integrate/ci-cd-integration/github-actions.md) uses this template shape to apply a plan after GitHub environment approval.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.terrakube.io/2.34.0/set-up/organizations/templates.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
