Terraform provides a declarative way to define AWS DynamoDB tables alongside the rest of an application stack. Using the aws_dynamodb_table resource, teams can codify table names, keys, capacity, streams, replicas and tags, and then apply, plan and drift-detect those definitions through terraform init, terraform plan and terraform apply. The resource integrates with the wider Terraform workflow for state locking, version control and repeatable deployments, and it can be used with both native AWS provider resources and community modules that wrap the same primitives.
Introduction
DynamoDB is a fully managed NoSQL service that integrates seamlessly with other AWS resources that may be part of your infrastructure. DynamoDB is often used with Terraform for several reasons:
- State locking — DynamoDB provides an effective mechanism for state locking in Terraform, which is crucial for preventing concurrent access to the same Terraform state file by multiple users or processes.
- Scalability and performance — DynamoDB offers high availability, scalability, and low-latency performance, making it an excellent choice for managing Terraform state.
- Integration with AWS services — DynamoDB is an AWS service, so it integrates seamlessly with other AWS resources that may be part of your infrastructure
- Managed service — DynamoDB is a fully managed service, which means you don’t have to worry about provisioning, patching, or managing the underlying infrastructure.
- Flexibility — DynamoDB supports document and key-value data models, providing flexibility in how you store and retrieve data related to your Terraform state.
- Automatic scaling — DynamoDB can automatically scale to meet the demands of your Terraform operations without manual intervention.
Terraform lets you define your DynamoDB tables and configurations alongside other resources like Lambda functions and API gateways, creating a complete configuration harnessing all the benefits of infrastructure as code for your application.
Defining a DynamoDB Table with Terraform
Terraform lets you define infrastructure like databases as code. This makes it easy to version control and share with others. In this article, I'll walk through the steps to set up a Terraform file and define a DynamoDB table in it. Then I'll apply the plan to create the real table in AWS. Following along will show you a hands-on example of using Terraform to manage infrastructure as code. The end result will be a DynamoDB table defined in a Terraform config that can be reused and shared.
What Is Terraform?
Terraform is an Infrastructure management tool. It facilitates automatically creating cloud resources through resource definition in the files. In the past, I would log into my cloud provider's console and click around to set up things like servers or databases. Doing it manually like that can be tedious and error-prone though. The terraform helps in overcoming this issue by automating the manual setups by defining the tasks and configuring the resources.
Features Of Terraform
The following are The the following are the Features Of Terraform that facilitate:
- Terraform Simplifying Infrastructure Deployment: With Terraform, instead of clicking through a UI, you simply write down what you want to build in a description file
A minimal configuration to get started. Refer to the Terraform Registry docs for all available arguments.
```
data "awsdynamodbtable" "example" {
Required arguments
Refer to the Terraform Registry docs for details
}
```
The aws_dynamodb_table data source provides details about a specific Dynamodb Table. A minimal configuration to get started.
Provider Configuration and Basic Attributes
Follow these steps to create a DynamoDB table using Terraform:
- Set up AWS credentials.
- Create a Terraform configuration file.
- Configure AWS provider
Configure AWS provider in Terraform
In your Terraform configuration file, specify the AWS provider and the region you want to work with:
provider "aws" {
region = "us-west-2" # Specify your desired region
}
Include DynamoDB table resource
Next, add the new DynamoDB table resource to the configuration file.
In this example, we will create one called ‘UsersTable’, using the resource awsdynamodbtable.
resource "aws_dynamodb_table" "users" {
name = "UsersTable"
billing_mode = "PROVISIONED"
read_capacity = 10
write_capacity = 5
hash_key = "userId"
attribute {
name = "userId"
type = "S" # String data type
}
tags = {
Name = "UsersTable"
}
}
Let’s take a look at this basic DynamoDB table in more detail:
billingmode is set toPROVISIONED, with read and write capacity units (RCUs and WCUs) defined.readcapacity andwritecapacity specify the initial read and write throughput for the table.hashkey defines the primary key for the table. Here, it’suserId which will be a string type (S).- The attribute block defines the schema for the table. Here, we have only theuserId attribute. - The tags block assigns a tag namedName to the table for easier identification.
We’ve created our first DynamoDB table in Terraform!
A comparable module example is:
module "dynamodb_table" {
source = "terraform-aws-modules/dynamodb-table/aws"
name = "my-table"
hash_key = "id"
attributes = [
{
name = "id"
type = "N"
}
]
tags = {
Terraform = "true"
Environment = "staging"
}
}
The module accepts name, hash_key, attributes and tags. The example shows a numeric hash key id of type N and tags Terraform = "true" and Environment = "staging".
Provisioned Capacity and Billing Modes
The core attributes that control table behavior are expressed in the resource block.
| Attribute | Example Value | Purpose |
|---|---|---|
| name | UsersTable | Logical table name in AWS |
| billing_mode | PROVISIONED | Capacity billing model |
| read_capacity | 10 | Initial RCUs when PROVISIONED |
| write_capacity | 5 | Initial WCUs when PROVISIONED |
| hash_key | userId | Primary key name |
| attribute name | userId | Key attribute name |
| attribute type | S | S for String, N for Number |
The attribute block defines the schema for the table. Here, we have only theuserId attribute.
Table Items and Data Sources
How to manage tables and items using Terraform?
To add items to your existing DynamoDB table, you can use the awsdynamodbtable_item resource
The example is shown below:
resource "aws_dynamodb_table_item" "user_item" {
table_name = aws_dynamodb_table.users.name
hash_key = "userId"
item = jsonencode({
"userId" = { "S" = "user123" }
"UserName" = { "S" = "Luke Skywalker" }
"Email" = { "S" = "[email protected]" }
})
}
You can then reference items in your Terraform table using the DynamoDB data source:
data "aws_dynamodb_table" "users" {
name = "UsersTable"
}
data "aws_dynamodb_table_item" "user_item" {
table_name = data.aws_dynamodb_table.users.name
key = jsonencode({
"userId" = { "S" = "user123" }
})
}
To remove tables and items from DynamoDB, you can simply remove them from your configuration files and run terraform apply. As they no longer exist in the configuration, they will be destroyed.
Autoscaling, Replicas, Streams and Lifecycle Warnings
Terraform execution plans for DynamoDB tables can show in-place updates for streams and replicas.
```
awsdynamodbtable.environment will be updated in-place
~ resource "awsdynamodbtable" "environment" {
id = "environmentpartiallyclearlypolishedmoth"
name = "environmentpartiallyclearlypolishedmoth"
~ streamenabled = false -> true
+ streamviewtype = "NEWANDOLDIMAGES"
tags = {}
(7 unchanged attributes hidden)
- replica {
- kmskeyarn = (known after apply)
- region_name = "ap-northeast-1"
} - replica {
- kmskeyarn = (known after apply)
- region_name = "us-west-1"
}
(8 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
```
The plan shows stream_enabled changing from false to true, addition of stream_view_type = "NEW_AND_OLD_IMAGES", and addition of replicas with region_name ap-northeast-1 and us-west-1 with kms_key_arn known after apply.
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
awsdynamodbtable.environment will be updated in-place
Warnings around autoscaling are significant when using the Terraform AWS modules.
Warning: enabling or disabling autoscaling can cause your table to be recreated
There are two separate Terraform resources used for the DynamoDB table: one is for when any autoscaling is enabled the other when disabled. If your table is already created and then you change the variable autoscalingenabled then your table will be recreated by Terraform. In this case you will need to move the old awsdynamodbtable resource that is being destroyed to the new resource that is being created. For example:
terraform state mv module.dynamodbtable.awsdynamodbtable.this module.dynamodbtable.awsdynamodb_table.autoscaled
When using an autoscaled provisioned table with GSIs you may find that applying TF changes whilst a GSI is scaled up will reset the capacity, there is an open issue for this on the AWS Provider. To get around this issue you can enable the ignorechangesglobalsecondaryindex setting however, using this setting means that any changes to GSIs will be ignored by Terraform and will hence have to be applied manually (or via some other automation).
NOTE: Setting ignorechangesglobalsecondaryindex after the table is already created causes your table to be recreated
Managing State and Preventing Destruction
How do you prevent destroy in Terraform DynamoDB table?
To prevent the destruction of resources managed by Terraform, particularly DynamoDB tables, you can use the prevent_destroy lifecycle rule within your Terraform code
You can then apply these configurations with Terraform commands (terraform init, terraform plan, terraform apply) to create, update, and manage the DynamoDB tables and their items.
| Terraform Command | Effect |
|---|---|
| terraform init | Initialize provider and modules |
| terraform plan | Preview changes without applying |
| terraform apply | Create, update, destroy resources per config |
Conclusion
Using aws_dynamodb_table gives full infrastructure as code control over DynamoDB schema, capacity, streams, replicas and tagging. Native resources allow explicit definition of billing_mode, read_capacity, write_capacity, hash_key, attribute blocks and tags, while community modules provide a higher-level abstraction with the same underlying resource. Autoscaling introduces a resource swap behavior that can cause recreation, requiring state moves and careful handling of GSIs with ignore_changes_global_secondary_index. Streams can be enabled in place with a view type such as NEW_AND_OLD_IMAGES, and replicas can be added per region. Items can be managed with aws_dynamodb_table_item and read back with data sources. Lifecycle rules like prevent_destroy protect production tables from accidental removal. The combination of provider configuration, resource definition, item management and lifecycle guardrails makes Terraform a durable way to define, version and share DynamoDB tables across environments.
Sources
- https://github.com/terraform-aws-modules/terraform-aws-dynamodb-table
- https://www.geeksforgeeks.org/devops/creating-aws-dynamodb-table-using-terraform/
- https://awsfundamentals.com/terraform/dynamodb/dynamodb-table-data
- https://spacelift.io/blog/terraform-dynamodb
- https://developer.hashicorp.com/terraform/tutorials/aws/aws-dynamodb-scale