Skip to content
Switch branches/tags
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Terra lets you write Terraform configurations using pure Clojure.


  1. Have the full power of Clojure at your fingertips when defining Terraform configurations.
  2. Do you need to iterate through something? Or maybe you need to automate part of the configuration creation? Just use the tools you are used to.
  3. No need to learn a separate configuration language in details. A simple Clojure EDN will do.

Table of Contents

Getting Started

Add the following dependency to your project.clj file:

Clojars Project

Add the following plugin to your :plugins in your project.clj file:

Clojars Project


Create a namespace in your project and require terra.core on your stateful component:

(ns my-project.infrastructure.core
  (:require [terra.core :as terra :refer [defterra $]))

Notice we are also referring the macros defterra and $.

We are going to create an example_ec2 definition using defterra. If you have done any Terraform before, this should be familiar to you.

(defterra example_ec2 {:provider {:aws {:region :us-east-1}}
                       :resource {:aws_instance {:example {:ami :ami-2757f631
                                                           :instance_type :t2.micro}}}})

According to this definiation, example_ec2 uses AWS in the us-east-1 region. It is a t2.micro instance using ami-2757f631. We have used keywords but strings also work if you prefer.

The next step is creating a handler function for trigering the generation of your Terraform file. Usually you just want to call terra/generate in it.

(defn handler []

Then add the following to your project.clj:

:terra {:handler my-project.infrastructure.core/handler}

Head to your terminal and type:

$ lein terra

You should see:

Terra: generating...
Terra: terraform/my-project.infrastructure.core/
Terra: done!

You can now plan and then apply your Terraform configuration by:

$ cd terraform/my-project.infrastructure.core
$ terraform plan
$ terraform apply

Since the terraform files are always generated, it is recommended that you add the terraform directory to your .gitignore.


The $ macro is a small utility helper to write Terraform interpolations in a more Clojure-like way.

For instance, in order to interpolate a variable, simply use:

:count ($ var.count)

If you want the entry :us-east-1 from the list var.amis, simply use:

:ami ($ (:us-east-1 var.amis))

The traditional get also works here:

:ami ($ (get var.amis :us-east-1))

This also works for indexes:

:ami ($ (get var.amis 0))

Last but not least, you can specify a call to Terraform's functions as if they were Clojure functions with:

:file ($ (file "path.txt"))

One last trick that might be interesting for you is that the defterra macro is just syntax sugar for a simple def. You can also specify your Terraform definitions by using the meta ^:terraform:

(def ^:terraform example_ec2 {:provider {:aws {:region :us-east-1}}
                              :resource {:aws_instance {:example {:ami :ami-2757f631
                                                                  :instance_type :t2.micro}}}})


If you find a bug, submit a Github issue.


This project is looking for team members who can help this project succeed! If you are interested in becoming a team member please open an issue.


Copyright © 2017 Tiago Luchini

Distributed under the MIT License.


Write Terraform configurations in pure Clojure.




No packages published