Terraform AWS backend for remote state files with S3 and DynamoDB


When using Terraform state files are normally generated locally in the directory where you run the scripts. This is fine for small scale deployments and testing  as an individual user. A problem arises when you involve multiple people, teams and even business units. 

With a remote state file all your teams and individuals share the same remote state file. This remote state file will always contain the latest state deployed to your account and environment, stored within S3. Including DynamoDB brings tracking functionality so that concurrent use of the state file will be blocked or “locked”.

For example User A runs the same terraform script to the same account as you at the same time. This would be an issue, but with DynamoDB this will not happen.


1 Create your S3 bucket and DynamoDB table

The S3 bucket and DynamoDB tables need to be in the same region. For this example we will choose us-east-1. It is best practice to have an entry point called main.tf. In this example these resources will be located there.

You can create this in two ways, through terraform or through the console. I will provide the terraform code but it is not necessary. If you do it through terraform make sure you specify your provider in provider.tf as such or provide it when you terraform apply.

provider "aws" {
  region = "us-east-1"

Create S3 Bucket

The S3 bucket will store your state files.

We will enable versioning and prevent its destruction through terraform. You can also enable versioning through the console. If you version your state files you will have a history of state file changes providing insight if something where to go wrong in the future. 


resource "aws_s3_bucket" "terraform_state_s3_bucket" {
    bucket = "unique-name-terraform-state-file-storage"
    versioning {
      enabled = true
    lifecycle {
      prevent_destroy = true
    tags {
      Name = "Terraform State File Storage"

Create DynamoDB table

The DynamoDB table provides the ability to lock the state file so multiple people do not alter the state file. 

Through the console the default settings should suffice. Just make sure your primary key is LockID.


resource "aws_dynamodb_table" "terraform_state_locking_dynamodb" {
  name = "terraform-state-locking"
  hash_key = "LockID"
  read_capacity = 20
  write_capacity = 20
  attribute {
    name = "LockID"
    type = "S"
  tags {
    Name = "Terraform State File Locking"

2 Create your backend.tf

It’s now time to create your backend.tf. Let’s go over what each of these variables mean below.

  • key – The path to the state file inside the bucket. When using a non-default workspace, the state path will be /workspace_key_prefix/workspace_name/key
  • region – The region of the S3 bucket and DynamoDB table.
  • bucket – The name of the S3 bucket.
  • dynamodb_table – The name of a DynamoDB table to use for state locking and consistency. The table must have a primary key named LockID. If not present, locking will be disabled.
  • encrypt – Whether to enable server side encryption of the state file.

More information regarding available backend configuration variables can be found here. 


The only part of the this backend.tf that will ever be altered is the key. You’ll want to specify a different key for different workspaces or different directories of terraform files. It’s a good idea to commit your backend.tf along with the rest of your terraform files into source control.


terraform {
 backend “s3” {
 key = path/to/my/key 
 region = us-east-1
 bucket = "unique-name-terraform-state-file-storage"
 dynamodb_table = "terraform-state-locking"
 encrypt = true # Optional, S3 Bucket Server Side Encryption


Place the backend.tf into one of your terraform directories and run terraform init. You’ll notice that it’s trying to initialize and configure your remote state file and if successful you’ll have some green text stating Successfully configured the backend "s3"! Terraform will automatically use this backend unless the backend configuration changes.

You can now run your terraform plan and terraform apply!

Prev post: Terraform nested double for-loopNext post: Making GoDaddy (or any other hosting) initial load faster

Related posts


  • Vince

    March 6, 2019 at 3:36 am

    Could you inform me what theme are you utilizing on your internet site? It looks good.

Leave a Reply

Your email address will not be published. Required fields are marked *