HashiCorp’s Terraform is a popular Infrastructure as Code (IaC) tool that helps DevOps teams codify their cloud infrastructure. While it’s a powerful tool that can help automate infrastructure provisioning, Terraform can have a steep learning curve.

To help you hit the ground running with Terraform, this guide will explore Terraform best practices in depth. After reading this guide, you’ll be familiar with Terraform best practices related to: 

  • Structure and style
  • The Terraform state file
  • Development
  • Deployment
  • Security 

Terraform best practices build on each other to form a pyramid.

Terraform Best Practices: An Overview

The table below provides an overview of Terraform best practices. The sections that follow will take a closer look at each best practice. . 

Structure and style best practices
Terraform best practice Description 
Use a consistent file structure and naming convention A consistent file structure and naming convention will keep maintenance effort low
Use variables appropriately Use the self variable, tfvars files, and avoid hard coding
Use the lookup function Data blocks can return maps so use lookup to parse the output
Use a tagging schema Clearly tagged resources help during security incidents and decrease troubleshooting time
Use modules where necessary Adhere to DRY principles and use modules to avoid repeating yourself
Use templates for things like AWS EC2 user-data Bash and HashiCorp Configuration Language (HCL) in the same file is messy and hard to maintain
Use format and validate Keep your files tidy by using the built-in format and validate features
State file best practices
Terraform best practice Description 
Store your state file remotely Configure a backend for your state files to avoid the risk of local state loss
Use one state per environment Development, testing and production environments must have their own state file for blast radius control
Set up state locking Avoid concurrent contention issues by configuring state locking
Development best practice
Terraform best practice Description 
Set up your IDE for streamlined development Preconfiguring your IDE enables significantly faster development 
Test your Terraform code Test Terraform code like you test your production software
Deployment best practices
Terraform best practice Description 
Automate your deployment with a CI / CD pipeline Use automated deployment for a consistent deployment environment
Use automated security scanning tools Use tools like checkov to detect misconfigurations
Security best practices
Terraform best practice Description 
Avoid passing credentials to terraform Instead, delegate permissions to the automated build environment using roles

Terraform Best Practices: Structure and Style

In their excellent 1999 book, The Pragmatic Programmer, Dave Thomas and Andy Hunt liken bad code and config to having broken windows:

“One broken window — a badly designed piece of code, a poor management decision that the team must live with for the duration of the project — is all it takes to start the decline. If you find yourself working on a project with quite a few broken windows, it’s all too easy to slip into the mindset of “All the rest of this code is crap, I’ll just follow suit.” It doesn’t matter if the project has been fine up to this point.”

Structure and style best practices are key to keeping good project hygiene and are the cornerstone of a healthy Terraform project. 

Use a consistent file structure and naming conventions

A person cleaning a screen. (Source).

Easy-to-read file structures and naming conventions future-proof your project. Maintainers won’t waste time trying to figure out what everything means. Instead, they can quickly and easily determine what the configuration does.


Use variables appropriately

Hard coding values in your Terraform configuration files will save you 30 seconds during development and cost you hours of debug time during deployment.

Use variables for everything and keep them all in the same place with a tfvars file.


Use the lookup function

Use the lookup function to retrieve values from a map using keys. You can define maps in your variables, and some data sources return maps of values.


Use a tagging schema

Define a common set of tags for your cloud resources and apply them in your Terraform.

This Terraform best practice enables cost allocation to projects and cost centers, quicker resolution of incidents, and reduced burden for your operations teams.


Use modules where necessary

Terraform allows you to define a set of resources in a module and call that module as many times as you like with different parameters.

If you find yourself copying code blocks multiple times to just change a few values, consider using a module instead.

With modules, DevOps teams can keep their code and configuration DRY, so be sure to avoid copy/pasting code blocks as much as practical.


Use templates for things like AWS EC2 user-data

Terraform allows you to include non-HCL text in your .tf files using <<EOF. While convenient, this makes templates hard to read.

Use templatefile to separate your non-HCL code and configuration from your Terraform templates.


Use format and validate

Terraform has a built-in function that automatically formats your configuration files. Consider running the formatter every time you save a file to avoid accidentally committing unformatted files (remember those broken windows).

Always run terraform validate before running terraform plan or apply. This will create a fast-feedback loop because validate is a local function that doesn’t need to communicate to your remote backend.

Modern IDEs have these features built-in, and you can install plugins in emacs and vim.


Terraform Best Practices: State File

Terraform keeps track of everything it deploys and what configuration was applied in a state file. It compares what is in the state file to remote resources to define what actions must be taken to align the current state and desired state.


Store your state file remotely

Configuring Terraform to save its state file remotely means you can offload the responsibility for its durability, resilience, and high-availability to a cloud provider. For example, you can enable versioning to save a full change history of your state file if you save your state to AWS S3.

Storing your state file remotely also eliminates the need to commit your state file to source control or edit it manually. Doing either will likely lead to state file conflicts and corruption.


Use one state per environment

Configure Terraform to save separate state files for each of your environments to ensure strong blast radius controls are in place, especially between your non-production and production workloads.


Set up state locking

When multiple developers are working on the same project and deploy at the same time, they might be trying to change the same resources. If two or more developers do change the same resource, you can run into conflicts.

Configure Terraform state locking to avoid conflicts.


Terraform Best Practices: Development

Terraform development best practices focus on how engineers write and test Terraform code and HCL.


Set up your IDE for streamlined development

Time spent streamlining your IDE upfront can save developers weeks in the long run.

If you regularly work with Terraform and HCL, set up syntax highlighting, auto-completion, documentation tooltips, and automatic formatting and validation of your templates.


Test your Terraform Code

A human relaxing at a desk while a robot works on a computer. (Source).

Write unit, contract, integration, and end-to-end tests for your Terraform code. The Terraform documentation has an excellent article on testing.

Use Terratest as an integration test to ensure your configuration files behave as expected.


Terraform Best Practices: Deployment

Automate your deployment with a CI / CD pipeline

Every developer has a different environment that can make getting consistent deploys challenging.

Automating your deployment using a CI / CD pipeline guarantees that every deployment is from an identical environment and reduces the chance of human error creating a failure.


Use automated security scanning tools

DevOps teams should run automated scans and checks of your code and configuration with tools like checkov for every commit.

Finding and fixing misconfigurations before they make it to production will save time, decrease the chance of security incidents, and help enforce security best practices.


Terraform Best Practices: Security

Security is paramount for any production-grade tool, and Terraform is no exception. In fact, with Terraform often codifying enterprise infrastructure across cloud providers, it is vital that DevOps teams harden and secure their Terraform configuration.


Avoid passing credentials to Terraform

Passing credentials for cloud providers to Terraform is usually a symptom of manual deployment patterns. To avoid manually passing credentials into Terraform, run your Terraform code from within the cloud provider in an automated pipeline.

This will also allow you to leverage role-based access patterns, like IAM Roles on AWS, for example.



Terraform is a powerful IaC tool that can help enterprises automate the process of configuring, securing, and scaling their infrastructure. By following the best practices we’ve outlined in this guide, you can help ensure your Terraform deployments are a success.

If you found these Terraform best practices useful, read the other articles in this series. They dig deep into Terraform features that you should be using in your day-to-day development.

  • Terraform Lookup – Streamline your Terraform code by using maps and lookup functions. Learn Terraform lookup function best practices through practical examples.
  • Terraform vs Ansible – Learn how Terraform and Anisble differ with respect to orchestration, programming paradigm, state management, cloud management, packaging and more.
  • Terraform Dynamic Block – Improve the speed, clarity, re-use, and reliability of your Terraform code. Learn the power of Terraform dynamic blocks and how to use them using practical examples.
  • Terraform For LoopTerraform for loops allow DevOps teams to iterate using its declarative language. In this article, we’ll show you how the syntax and usage of for loops in Terraform.
  • Understanding Terraform TemplatesTerraform templates are a powerful tool for automating your Infrastructure as Code workload. In this article, we explore the how and why of Terraform templates with hands-on code samples.
  • Terraform CommandsLearn the most important Terraform commands with full code samples and screenshots to guide you through their usage.
  • Terraform TagsTags are key-value pairs, that contain descriptive metadata. This article will teach you everything you need to master Terraform tags and optimize your cloud configuration.
  • Terraform FunctionsTerraform functions are a built-in feature of Terraform that enables more maintainable code. This guide will demystify Terraform functions to help you have a better infrastructure-as-code experience.
  • Terraform Screenshots: Practical ExamplesLearn how to set up Terraform, use the AWS cloud platform provider plugin, and manipulate an EC2 instance through code snippets and screenshots.
  • Terraform Import Examples Learn to add external resources and avoid pitfalls through a Terraform import example containing full code samples and screenshots to guide you through the usage. 
  • Pulumi vs. TerraformInfrastructure as Code (IaC) is the best way to manage cloud infrastructure. Explore the benefits and differences between two of the most popular IaC solutions, Pulumi and Terraform.
  • More chapters coming soon!