Creating reliable asynchronous communication in AWS requires message queuing that can be provisioned consistently across environments. Amazon Simple Queue Service is a fully managed message queuing service that helps decouple and scale distributed applications. Using Terraform to provision and manage SQS queues ensures consistent, automated, and repeatable infrastructure deployments. This article shows how to define and configure an Amazon SQS queue using Terraform and provide example configurations that streamline message handling in cloud architecture.
Amazon SQS is a fully managed message queuing service that enables decoupling of distributed systems by allowing asynchronous communication between microservices and other components. SQS works by temporarily storing messages in a queue until they are retrieved and processed by a consuming service. This improves system resilience and scalability by isolating producers from consumers. By defining queues declaratively, teams can manage lifecycle changes and maintain version control over messaging components. As part of a scalable cloud-native design, Terraform-managed SQS queues support both high-throughput and decoupled application architectures across development environments.
What Is an SQS Queue and Terraform Context
Amazon Simple Queue Service is a fully managed message queuing service that enables decoupling of distributed systems by allowing asynchronous communication between microservices and other components.
Terraform is an open-source infrastructure as-code apparatus that permits clients to characterize and arrangement cloud infrastructure resources utilizing declarative configuration files. Infrastructure as-Code is a way to deal with overseeing and provisioning foundation assets utilizing code as opposed to manual cycles.
A queue in SQS is a named place where messages are put away. It acts as a buffer between message producers and customers, allowing asynchronous correspondence between disseminated parts of an application.
SQS Topic is a legitimate substance used to coordinate and manage related SQS queues. It works with pub/sub messaging patterns, where messages published to the point are circulated to subscribing in ques or endpoints. Pub/Sub Messaging is a communication design where managing send messages to a central point, and supporters get messages from that topic. SQS topics empower pub/sub messaging, permitting decoupled correspondence between components.
When queues are managed with Terraform, standards can be codified so every new queue follows the same rules. Your producers then send messages to the queue URL, and your consumers poll it.
Defining the Terraform Resource and Importing Existing Queues
Define the Terraform resource by adding an awssqsqueue resource to your Terraform configuration that represents the existing queue. Start with a minimal block:
hcl
resource "aws_sqs_queue" "orders_queue" {
name = "orders-queue"
# Optional: fill in settings to match the existing queue
# visibility_timeout_seconds = 60
# message_retention_seconds = 345600
# ...
}
The resource name orders_queue in this example is internal to Terraform. The name argument must match the real SQS queue name.
After importing, you can run terraform state show aws_sqs_queue.orders_queue to see the full set of arguments and align your configuration. Only add arguments in your HCL that you actually want Terraform to manage and leave computed attributes out of the configuration.
Run the import once the resource exists in your .tf files. Run terraform init if you haven't already, then import the queue:
hcl
terraform import aws_sqs_queue.orders_queue https://sqs.eu-central-1.amazonaws.com/123456789012/orders-queue
This tells Terraform:
- Use the resource aws_sqs_queue.orders_queue in the config
- Link it to the existing SQS queue with that URL.
If you use a newer Terraform version you can also define an import block in your configuration instead of running terraform import, but the command shown here is still supported and simple to use. After the import completes run terraform plan to see any differences between your configuration and the actual queue.
Example 1 Production Queue With Custom Behavior
An AWS SQS queue in Terraform is just a resource block that describes how your queue should behave. In a production environment, you usually want:
- A main queue for normal messages
- A dead letter queue for messages that keep failing
- Sensible timeouts and retention settings
The configuration below shows a common production pattern for a Terraform SQS queue:
```hcl
provider "aws" {
region = "eu-central-1"
}
Dead letter queue
resource "awssqsqueue" "ordersdlq" {
name = "orders-dlq"
messageretention_seconds = 1209600 # 14 days
tags = {
Environment = "production"
Service = "orders"
}
}
Main production queue
resource "awssqsqueue" "ordersqueue" {
name = "orders-queue"
# How long a worker has to process a message
visibilitytimeoutseconds = 60
# Keep messages for 4 days
messageretentionseconds = 345600
# Optional delivery delay for new messages
delayseconds = 0
# Long polling to reduce empty receives
receivewaittimeseconds = 20
# Move failing messages to the DLQ after 5 failed receives
redrivepolicy = jsonencode({
deadLetterTargetArn = awssqsqueue.orders_dlq.arn
maxReceiveCount = 5
})
tags = {
Environment = "production"
Service = "orders"
}
}
```
The orders_queue is your main production queue where the application publishes messages. Tags mark both queues as part of the production orders service so it is clear in the AWS console what they belong to.
If you plug this Terraform SQS queue into a worker service such as ECS, EKS, or Lambda, you get a clean and predictable production setup that is easy to reason about and safe by default.
| Attribute | Example Value | Purpose |
|---|---|---|
| visibilitytimeoutseconds | 60 | How long a worker has to process a message |
| messageretentionseconds | 345600 | Keep messages for 4 days |
| delay_seconds | 0 | Optional delivery delay for new messages |
| receivewaittime_seconds | 20 | Long polling to reduce empty receives |
| redrive_policy.maxReceiveCount | 5 | Move failing messages to DLQ after 5 failed receives |
| messageretentionseconds DLQ | 1209600 | 14 days retention for dead letter queue |
Example 2 Secure Encrypted Queue For Sensitive Data
You can create a secure, encrypted SQS queue in Terraform by combining three things: the queue itself, a KMS key for encryption, and an optional queue policy that controls who can send and receive messages.
```hcl
provider "aws" {
region = "eu-central-1"
}
Customer managed KMS key for SQS encryption
resource "awskmskey" "sensitivedata" {
description = "KMS key for encrypting sensitive SQS messages"
enablekey_rotation = true
}
resource "awskmsalias" "sensitivedata" {
name = "alias/sensitive-sqs-queue"
targetkeyid = awskmskey.sensitivedata.key_id
}
Secure encrypted SQS queue
resource "awssqsqueue" "sensitivedata" {
name = "sensitive-data-queue"
kmsmasterkeyid = awskmskey.sensitivedata.arn
kmsdatakeyreuseperiodseconds = 300
# Encryption at rest + tight access window
visibilitytimeoutseconds = 30
messageretentionseconds = 86400 # 1 day
delayseconds = 0
fifoqueue = false
# Optional dead letter queue support would go here
}
Restrictive queue policy
data "awsiampolicydocument" "sensitivedata_queue" {
statement {
sid = "AllowSpecificRoleOnly"
principals {
type =
}
}
}
```
This pattern provides encryption at rest with a customer managed KMS key, key rotation enabled, and a short data key reuse period. Visibility timeout and message retention are tightened for sensitive data.
FIFO Queue Example
An Example of a FIFO Queue is covered in the reference material as a distinct configuration pattern. FIFO queues require the .fifo suffix in the name and provide strict ordering guarantees. Naming conventions for FIFO queues are addressed in the naming section below.
Naming Conventions and Centralization
SQS queues in Terraform naming conventions use a consistent naming scheme that encodes the environment, service, and purpose of the queue.
Use a consistent naming scheme that encodes the environment, service, and purpose of the queue:
- Prefer kebab-case names, for example:
- orders-events-queue
- orders-events-dlq
- payments-refunds-fifo
- Include the environment in the name where helpful:
- orders-queue-dev
- orders-queue-staging
- orders-queue-prod
- Include the service or domain to avoid collisions across teams:
- inventory-updates-queue
- billing-notifications-queue
- Use clear suffixes:
- -dlq or -dead-letter for dead-letter queues
- .fifo for FIFO queues, as required by AWS, for example orders-events.fifo and orders-events-dlq.fifo
In Terraform, centralize names via variables or locals so they are easy to reuse:
```hcl
locals {
env = "prod"
servicename = "orders"
mainqueue = "${local.servicename}-queue-${local.env}"
dlqqueue = "${local.service_name}-dlq-${local.env}"
}
resource "awssqsqueue" "ordersqueue" {
name = local.mainqueue
# ...
}
resource "awssqsqueue" "ordersdlq" {
name = local.dlqqueue
# ...
}
```
This keeps queue names predictable, making it easier to find related resources in CloudWatch logs, IAM policies, and the AWS console.
| Naming Element | Example | Rule |
|---|---|---|
| Service | orders | Include service or domain |
| Environment | prod | Append -dev, -staging, -prod |
| Purpose | queue, dlq | Use clear suffixes |
| Style | kebab-case | Prefer kebab-case names |
| FIFO | .fifo | Required suffix for FIFO queues |
Permissions and Access Control
Permissions and access control treat each queue as a boundary and apply least privilege to the IAM roles and queue policies that interact with it.
When you manage queues with Terraform, you can codify these standards so every new queue follows the same rules. Treat each queue as a boundary and apply least privilege to the IAM roles and queue policies that interact with it.
A restrictive queue policy is used to only allow a specific IAM role to access the queue. The example for sensitive data shows a data source aws_iam_policy_document with statement AllowSpecificRoleOnly and principals configuration.
Best Practices Summary
What we’ll cover in practice includes:
- What is an SQS Queue?
- How to use SQS Queue in Terraform
- Example 1: Production queue with custom behavior
- Example 2: Secure encrypted queue for sensitive data
- Example of a FIFO Queue
- How to import existing AWS SQS queues into Terraform state
- Best practices for naming and permissions of SQS queues in Terraform
Automate Terraform deployments with Spacelift to automate infrastructure provisioning and build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization, and many more.
Conclusion
Terraform-managed SQS queues provide declarative control over message queuing behavior in AWS. Defining queues with awssqsqueue resources allows teams to codify production patterns including dead letter queues, visibility timeouts, message retention, long polling, and redrive policies. Encryption with customer managed KMS keys adds a security layer for sensitive data, while queue policies enforce least privilege access.
Naming conventions that encode environment, service, and purpose with kebab-case and explicit suffixes such as -dlq and .fifo keep resources discoverable across CloudWatch, IAM, and the AWS console. Centralizing names via locals or variables prevents drift and enables reuse.
Importing existing queues into Terraform state with terraform import links live SQS URLs to declarative configuration, allowing plan-driven alignment without recreation. Once imported, teams can run terraform plan to see differences and only manage arguments they intend to control.
The combination of declarative provisioning, consistent naming, production-ready dead letter handling, and encryption makes Terraform SQS queues a stable foundation for high-throughput, decoupled application architectures across development environments.