Create and Configure SQS Queues

The aws:sqs/queue:Queue resource, part of the Pulumi AWS provider, provisions an SQS queue that acts as a message buffer between producers and consumers in distributed systems. This guide focuses on three capabilities: standard and FIFO queue configuration, dead letter queue routing, and encryption options.

SQS queues may reference dead letter queues by ARN and KMS keys for encryption. The examples are intentionally small. Combine them with your own IAM policies, Lambda triggers, and monitoring.

Configure a standard queue with tuning and dead letter handling

Most deployments start with a standard queue that buffers messages between services, with tuning for delivery timing and message retention.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const queue = new aws.sqs.Queue("queue", {
    name: "example-queue",
    delaySeconds: 90,
    maxMessageSize: 2048,
    messageRetentionSeconds: 86400,
    receiveWaitTimeSeconds: 10,
    redrivePolicy: JSON.stringify({
        deadLetterTargetArn: queueDeadletter.arn,
        maxReceiveCount: 4,
    }),
    tags: {
        Environment: "production",
    },
});
import pulumi
import json
import pulumi_aws as aws

queue = aws.sqs.Queue("queue",
    name="example-queue",
    delay_seconds=90,
    max_message_size=2048,
    message_retention_seconds=86400,
    receive_wait_time_seconds=10,
    redrive_policy=json.dumps({
        "deadLetterTargetArn": queue_deadletter["arn"],
        "maxReceiveCount": 4,
    }),
    tags={
        "Environment": "production",
    })
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sqs"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"deadLetterTargetArn": queueDeadletter.Arn,
			"maxReceiveCount":     4,
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = sqs.NewQueue(ctx, "queue", &sqs.QueueArgs{
			Name:                    pulumi.String("example-queue"),
			DelaySeconds:            pulumi.Int(90),
			MaxMessageSize:          pulumi.Int(2048),
			MessageRetentionSeconds: pulumi.Int(86400),
			ReceiveWaitTimeSeconds:  pulumi.Int(10),
			RedrivePolicy:           pulumi.String(json0),
			Tags: pulumi.StringMap{
				"Environment": pulumi.String("production"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var queue = new Aws.Sqs.Queue("queue", new()
    {
        Name = "example-queue",
        DelaySeconds = 90,
        MaxMessageSize = 2048,
        MessageRetentionSeconds = 86400,
        ReceiveWaitTimeSeconds = 10,
        RedrivePolicy = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["deadLetterTargetArn"] = queueDeadletter.Arn,
            ["maxReceiveCount"] = 4,
        }),
        Tags = 
        {
            { "Environment", "production" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sqs.Queue;
import com.pulumi.aws.sqs.QueueArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var queue = new Queue("queue", QueueArgs.builder()
            .name("example-queue")
            .delaySeconds(90)
            .maxMessageSize(2048)
            .messageRetentionSeconds(86400)
            .receiveWaitTimeSeconds(10)
            .redrivePolicy(serializeJson(
                jsonObject(
                    jsonProperty("deadLetterTargetArn", queueDeadletter.arn()),
                    jsonProperty("maxReceiveCount", 4)
                )))
            .tags(Map.of("Environment", "production"))
            .build());

    }
}
resources:
  queue:
    type: aws:sqs:Queue
    properties:
      name: example-queue
      delaySeconds: 90
      maxMessageSize: 2048
      messageRetentionSeconds: 86400
      receiveWaitTimeSeconds: 10
      redrivePolicy:
        fn::toJSON:
          deadLetterTargetArn: ${queueDeadletter.arn}
          maxReceiveCount: 4
      tags:
        Environment: production

The delaySeconds property postpones initial delivery of all messages. The receiveWaitTimeSeconds enables long polling, reducing empty responses and API costs. The redrivePolicy routes messages that fail processing repeatedly to a dead letter queue after maxReceiveCount attempts. The deadLetterTargetArn must reference an existing queue.

Create a FIFO queue with content-based deduplication

Applications requiring exactly-once processing and strict ordering use FIFO queues instead of standard queues.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const queue = new aws.sqs.Queue("queue", {
    name: "example-queue.fifo",
    fifoQueue: true,
    contentBasedDeduplication: true,
});
import pulumi
import pulumi_aws as aws

queue = aws.sqs.Queue("queue",
    name="example-queue.fifo",
    fifo_queue=True,
    content_based_deduplication=True)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sqs"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sqs.NewQueue(ctx, "queue", &sqs.QueueArgs{
			Name:                      pulumi.String("example-queue.fifo"),
			FifoQueue:                 pulumi.Bool(true),
			ContentBasedDeduplication: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var queue = new Aws.Sqs.Queue("queue", new()
    {
        Name = "example-queue.fifo",
        FifoQueue = true,
        ContentBasedDeduplication = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sqs.Queue;
import com.pulumi.aws.sqs.QueueArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var queue = new Queue("queue", QueueArgs.builder()
            .name("example-queue.fifo")
            .fifoQueue(true)
            .contentBasedDeduplication(true)
            .build());

    }
}
resources:
  queue:
    type: aws:sqs:Queue
    properties:
      name: example-queue.fifo
      fifoQueue: true
      contentBasedDeduplication: true

Setting fifoQueue to true enables first-in-first-out delivery and exactly-once processing. The contentBasedDeduplication property uses message body hashing to detect duplicates automatically, eliminating the need for application-generated deduplication IDs. FIFO queue names must end with the .fifo suffix.

Scale FIFO throughput with per-message-group quotas

High-volume FIFO workloads can exceed the default 300 transactions per second limit by partitioning across message groups.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const queue = new aws.sqs.Queue("queue", {
    name: "pulumi-example-queue.fifo",
    fifoQueue: true,
    deduplicationScope: "messageGroup",
    fifoThroughputLimit: "perMessageGroupId",
});
import pulumi
import pulumi_aws as aws

queue = aws.sqs.Queue("queue",
    name="pulumi-example-queue.fifo",
    fifo_queue=True,
    deduplication_scope="messageGroup",
    fifo_throughput_limit="perMessageGroupId")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sqs"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sqs.NewQueue(ctx, "queue", &sqs.QueueArgs{
			Name:                pulumi.String("pulumi-example-queue.fifo"),
			FifoQueue:           pulumi.Bool(true),
			DeduplicationScope:  pulumi.String("messageGroup"),
			FifoThroughputLimit: pulumi.String("perMessageGroupId"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var queue = new Aws.Sqs.Queue("queue", new()
    {
        Name = "pulumi-example-queue.fifo",
        FifoQueue = true,
        DeduplicationScope = "messageGroup",
        FifoThroughputLimit = "perMessageGroupId",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sqs.Queue;
import com.pulumi.aws.sqs.QueueArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var queue = new Queue("queue", QueueArgs.builder()
            .name("pulumi-example-queue.fifo")
            .fifoQueue(true)
            .deduplicationScope("messageGroup")
            .fifoThroughputLimit("perMessageGroupId")
            .build());

    }
}
resources:
  queue:
    type: aws:sqs:Queue
    properties:
      name: pulumi-example-queue.fifo
      fifoQueue: true
      deduplicationScope: messageGroup
      fifoThroughputLimit: perMessageGroupId

The fifoThroughputLimit property controls whether the 300 TPS quota applies to the entire queue (perQueue) or per message group (perMessageGroupId). Setting deduplicationScope to messageGroup enables independent deduplication within each group. This configuration allows each message group to process up to 300 TPS independently.

Enable encryption with SQS-managed keys

Compliance requirements often mandate encryption at rest. SQS-managed encryption provides automatic key management without KMS costs.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const queue = new aws.sqs.Queue("queue", {
    name: "pulumi-example-queue",
    sqsManagedSseEnabled: true,
});
import pulumi
import pulumi_aws as aws

queue = aws.sqs.Queue("queue",
    name="pulumi-example-queue",
    sqs_managed_sse_enabled=True)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sqs"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sqs.NewQueue(ctx, "queue", &sqs.QueueArgs{
			Name:                 pulumi.String("pulumi-example-queue"),
			SqsManagedSseEnabled: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var queue = new Aws.Sqs.Queue("queue", new()
    {
        Name = "pulumi-example-queue",
        SqsManagedSseEnabled = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sqs.Queue;
import com.pulumi.aws.sqs.QueueArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var queue = new Queue("queue", QueueArgs.builder()
            .name("pulumi-example-queue")
            .sqsManagedSseEnabled(true)
            .build());

    }
}
resources:
  queue:
    type: aws:sqs:Queue
    properties:
      name: pulumi-example-queue
      sqsManagedSseEnabled: true

Setting sqsManagedSseEnabled to true encrypts messages using SQS-owned keys. SQS handles key rotation and management automatically. This option provides encryption without additional KMS charges or key configuration.

Encrypt messages with customer-managed KMS keys

Organizations with strict key policies use customer-managed KMS keys to control encryption, rotation, and audit trails.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const queue = new aws.sqs.Queue("queue", {
    name: "example-queue",
    kmsMasterKeyId: "alias/aws/sqs",
    kmsDataKeyReusePeriodSeconds: 300,
});
import pulumi
import pulumi_aws as aws

queue = aws.sqs.Queue("queue",
    name="example-queue",
    kms_master_key_id="alias/aws/sqs",
    kms_data_key_reuse_period_seconds=300)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sqs"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sqs.NewQueue(ctx, "queue", &sqs.QueueArgs{
			Name:                         pulumi.String("example-queue"),
			KmsMasterKeyId:               pulumi.String("alias/aws/sqs"),
			KmsDataKeyReusePeriodSeconds: pulumi.Int(300),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var queue = new Aws.Sqs.Queue("queue", new()
    {
        Name = "example-queue",
        KmsMasterKeyId = "alias/aws/sqs",
        KmsDataKeyReusePeriodSeconds = 300,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sqs.Queue;
import com.pulumi.aws.sqs.QueueArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var queue = new Queue("queue", QueueArgs.builder()
            .name("example-queue")
            .kmsMasterKeyId("alias/aws/sqs")
            .kmsDataKeyReusePeriodSeconds(300)
            .build());

    }
}
resources:
  queue:
    type: aws:sqs:Queue
    properties:
      name: example-queue
      kmsMasterKeyId: alias/aws/sqs
      kmsDataKeyReusePeriodSeconds: 300

The kmsMasterKeyId property specifies the KMS key for encryption. The kmsDataKeyReusePeriodSeconds controls how long SQS reuses a data key before requesting a new one from KMS, balancing security and KMS API costs. The default is 300 seconds (5 minutes).

Beyond these examples

These snippets focus on specific queue-level features: standard and FIFO queue types, dead letter queue routing, and encryption with SQS-managed and KMS keys. They’re intentionally minimal rather than full messaging architectures.

The examples may reference pre-existing infrastructure such as dead letter queues (by ARN) and KMS keys for SSE-KMS encryption. They focus on configuring the queue rather than provisioning surrounding infrastructure.

To keep things focused, common queue patterns are omitted, including:

  • Visibility timeout configuration (visibilityTimeoutSeconds)
  • IAM access policies (policy property, prefer aws.sqs.QueuePolicy)
  • Redrive allow policies (redriveAllowPolicy, prefer aws.sqs.RedriveAllowPolicy)
  • Tag-based organization and cost tracking

These omissions are intentional: the goal is to illustrate how each queue feature is wired, not provide drop-in messaging modules. See the SQS Queue resource reference for all available configuration options.

Let's create and Configure SQS Queues

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Common Errors & Pitfalls
Why is my queue creation or update timing out?
Queue operations hang indefinitely with a “timeout while waiting” error when using aws.sqs.QueuePolicy without explicitly setting Version = "2012-10-17" in the policy JSON.
Why am I getting an error with maxReceiveCount in my dead letter queue configuration?
The maxReceiveCount parameter in redrivePolicy must be specified as an integer (5), not a string (“5”).
Why can't I create a FIFO queue?
FIFO queue names must end with the .fifo suffix. Ensure your name property ends with .fifo and fifoQueue is set to true.
Queue Types & Configuration
What's the difference between standard and FIFO queues?
Standard queues (default) offer maximum throughput and at-least-once delivery. FIFO queues guarantee exactly-once processing and message ordering. To create a FIFO queue, set fifoQueue to true and ensure the queue name ends with .fifo.
How do I enable high-throughput mode for FIFO queues?
Set deduplicationScope to messageGroup and fifoThroughputLimit to perMessageGroupId. This applies throughput quotas per message group instead of per queue.
What properties can't I change after creating a queue?
The name, namePrefix, and fifoQueue properties are immutable. You cannot convert between standard and FIFO queues or rename a queue after creation.
Dead Letter Queues
How do I set up a dead letter queue?
Configure redrivePolicy with deadLetterTargetArn (the ARN of your dead letter queue) and maxReceiveCount (integer specifying retry attempts before moving to DLQ). Use aws.sqs.RedriveAllowPolicy on the DLQ to control which source queues can use it.
Should I use inline policies or separate policy resources?
Use dedicated resources (aws.sqs.QueuePolicy, aws.sqs.RedrivePolicy, aws.sqs.RedriveAllowPolicy) instead of inline policy, redrivePolicy, or redriveAllowPolicy properties. The provider only performs drift detection on inline policies when present in configuration.
Encryption & Security
What encryption options are available for SQS queues?

You have two options:

  1. SSE-SQS - Set sqsManagedSseEnabled to true for encryption with SQS-owned keys
  2. SSE-KMS - Set kmsMasterKeyId to a KMS key ID (e.g., alias/aws/sqs) and optionally configure kmsDataKeyReusePeriodSeconds (default 300 seconds, range 60-86400)
Message Handling & Timing
What's the difference between short polling and long polling?
Short polling (default) returns immediately if no messages are available (receiveWaitTimeSeconds = 0). Long polling waits up to 20 seconds for messages to arrive, reducing empty responses and costs. Set receiveWaitTimeSeconds to 1-20 to enable long polling.
What are the message retention and timing limits?
  • Message retention: 60 seconds (1 minute) to 1,209,600 seconds (14 days), default 345,600 seconds (4 days)
  • Delivery delay: 0 to 900 seconds (15 minutes), default 0
  • Visibility timeout: 0 to 43,200 seconds (12 hours), default 30 seconds

Using a different cloud?

Explore messaging guides for other cloud providers: