Skip to content
v2.274.0

Amazon Simple Queue Service Construct Library ​

Amazon Simple Queue Service (SQS) is a fully managed message queuing service that enables you to decouple and scale microservices, distributed systems, and serverless applications. SQS eliminates the complexity and overhead associated with managing and operating message oriented middleware, and empowers developers to focus on differentiating work. Using SQS, you can send, store, and receive messages between software components at any volume, without losing messages or requiring other services to be available.

Installation ​

Import to your project:

ts
import * as sqs from 'aws-cdk-lib/aws-sqs';
python
import aws_cdk.aws_sqs as sqs
java
import software.amazon.awscdk.services.sqs.*;
csharp
using Amazon.CDK.AWS.SQS;
go
import sqs "github.com/aws/aws-cdk-go/awscdk"

Basic usage ​

Here's how to add a basic queue to your application:

ts
new sqs.Queue(this, 'Queue');
python
sqs.Queue(self, "Queue")
java
new Queue(this, "Queue");
csharp
new Queue(this, "Queue");
go
sqs.NewQueue(this, jsii.String("Queue"))

Encryption ​

By default queues are encrypted using SSE-SQS. If you want to change the encryption mode, set the encryption property. The following encryption modes are supported:

  • KMS key that SQS manages for you
  • KMS key that you can managed yourself
  • Server-side encryption managed by SQS (SSE-SQS)
  • Unencrypted

To learn more about SSE-SQS on Amazon SQS, please visit the Amazon SQS documentation.

ts
// Use managed key
new sqs.Queue(this, 'Queue', {
  encryption: sqs.QueueEncryption.KMS_MANAGED,
});

// Use custom key
const myKey = new kms.Key(this, 'Key');

new sqs.Queue(this, 'Queue', {
  encryption: sqs.QueueEncryption.KMS,
  encryptionMasterKey: myKey,
});

// Use SQS managed server side encryption (SSE-SQS)
new sqs.Queue(this, 'Queue', {
  encryption: sqs.QueueEncryption.SQS_MANAGED,
});

// Unencrypted queue
new sqs.Queue(this, 'Queue', {
  encryption: sqs.QueueEncryption.UNENCRYPTED,
});
python
# Use managed key
sqs.Queue(self, "Queue",
    encryption=sqs.QueueEncryption.KMS_MANAGED
)

# Use custom key
my_key = kms.Key(self, "Key")

sqs.Queue(self, "Queue",
    encryption=sqs.QueueEncryption.KMS,
    encryption_master_key=my_key
)

# Use SQS managed server side encryption (SSE-SQS)
sqs.Queue(self, "Queue",
    encryption=sqs.QueueEncryption.SQS_MANAGED
)

# Unencrypted queue
sqs.Queue(self, "Queue",
    encryption=sqs.QueueEncryption.UNENCRYPTED
)
java
// Use managed key
// Use managed key
Queue.Builder.create(this, "Queue")
        .encryption(QueueEncryption.KMS_MANAGED)
        .build();

// Use custom key
Key myKey = new Key(this, "Key");

Queue.Builder.create(this, "Queue")
        .encryption(QueueEncryption.KMS)
        .encryptionMasterKey(myKey)
        .build();

// Use SQS managed server side encryption (SSE-SQS)
// Use SQS managed server side encryption (SSE-SQS)
Queue.Builder.create(this, "Queue")
        .encryption(QueueEncryption.SQS_MANAGED)
        .build();

// Unencrypted queue
// Unencrypted queue
Queue.Builder.create(this, "Queue")
        .encryption(QueueEncryption.UNENCRYPTED)
        .build();
csharp
// Use managed key
// Use managed key
new Queue(this, "Queue", new QueueProps {
    Encryption = QueueEncryption.KMS_MANAGED
});

// Use custom key
var myKey = new Key(this, "Key");

new Queue(this, "Queue", new QueueProps {
    Encryption = QueueEncryption.KMS,
    EncryptionMasterKey = myKey
});

// Use SQS managed server side encryption (SSE-SQS)
// Use SQS managed server side encryption (SSE-SQS)
new Queue(this, "Queue", new QueueProps {
    Encryption = QueueEncryption.SQS_MANAGED
});

// Unencrypted queue
// Unencrypted queue
new Queue(this, "Queue", new QueueProps {
    Encryption = QueueEncryption.UNENCRYPTED
});
go
// Use managed key
// Use managed key
sqs.NewQueue(this, jsii.String("Queue"), &QueueProps{
	Encryption: sqs.QueueEncryption_KMS_MANAGED,
})

// Use custom key
myKey := kms.NewKey(this, jsii.String("Key"))

sqs.NewQueue(this, jsii.String("Queue"), &QueueProps{
	Encryption: sqs.QueueEncryption_KMS,
	EncryptionMasterKey: myKey,
})

// Use SQS managed server side encryption (SSE-SQS)
// Use SQS managed server side encryption (SSE-SQS)
sqs.NewQueue(this, jsii.String("Queue"), &QueueProps{
	Encryption: sqs.QueueEncryption_SQS_MANAGED,
})

// Unencrypted queue
// Unencrypted queue
sqs.NewQueue(this, jsii.String("Queue"), &QueueProps{
	Encryption: sqs.QueueEncryption_UNENCRYPTED,
})

Encryption in transit ​

If you want to enforce encryption of data in transit, set the enforceSSL property to true. A resource policy statement that allows only encrypted connections over HTTPS (TLS) will be added to the queue.

ts
new sqs.Queue(this, 'Queue', {
  enforceSSL: true,
});
python
sqs.Queue(self, "Queue",
    enforce_ssl=True
)
java
Queue.Builder.create(this, "Queue")
        .enforceSSL(true)
        .build();
csharp
new Queue(this, "Queue", new QueueProps {
    EnforceSSL = true
});
go
sqs.NewQueue(this, jsii.String("Queue"), &QueueProps{
	EnforceSSL: jsii.Boolean(true),
})

First-In-First-Out (FIFO) queues ​

FIFO queues give guarantees on the order in which messages are dequeued, and have additional features in order to help guarantee exactly-once processing. For more information, see the SQS manual. Note that FIFO queues are not available in all AWS regions.

A queue can be made a FIFO queue by either setting fifo: true, giving it a name which ends in ".fifo", or by enabling a FIFO specific feature such as: content-based deduplication, deduplication scope or fifo throughput limit.

Dead letter source queues permission ​

You can configure the permission settings for queues that can designate the created queue as their dead-letter queue using the redriveAllowPolicy attribute.

By default, all queues within the same account and region are permitted as source queues.

ts
declare const sourceQueue: sqs.IQueue;

// Only the sourceQueue can specify this queue as the dead-letter queue.
const queue1 = new sqs.Queue(this, 'Queue2', {
  redriveAllowPolicy: {
    sourceQueues: [sourceQueue],
  }
});

// No source queues can specify this queue as the dead-letter queue.
const queue2 = new sqs.Queue(this, 'Queue', {
  redriveAllowPolicy: {
    redrivePermission: sqs.RedrivePermission.DENY_ALL,
  }
});
python
# source_queue: sqs.IQueue


# Only the sourceQueue can specify this queue as the dead-letter queue.
queue1 = sqs.Queue(self, "Queue2",
    redrive_allow_policy=sqs.RedriveAllowPolicy(
        source_queues=[source_queue]
    )
)

# No source queues can specify this queue as the dead-letter queue.
queue2 = sqs.Queue(self, "Queue",
    redrive_allow_policy=sqs.RedriveAllowPolicy(
        redrive_permission=sqs.RedrivePermission.DENY_ALL
    )
)
java
IQueue sourceQueue;


// Only the sourceQueue can specify this queue as the dead-letter queue.
Queue queue1 = Queue.Builder.create(this, "Queue2")
        .redriveAllowPolicy(RedriveAllowPolicy.builder()
                .sourceQueues(List.of(sourceQueue))
                .build())
        .build();

// No source queues can specify this queue as the dead-letter queue.
Queue queue2 = Queue.Builder.create(this, "Queue")
        .redriveAllowPolicy(RedriveAllowPolicy.builder()
                .redrivePermission(RedrivePermission.DENY_ALL)
                .build())
        .build();
csharp
IQueue sourceQueue;


// Only the sourceQueue can specify this queue as the dead-letter queue.
var queue1 = new Queue(this, "Queue2", new QueueProps {
    RedriveAllowPolicy = new RedriveAllowPolicy {
        SourceQueues = new [] { sourceQueue }
    }
});

// No source queues can specify this queue as the dead-letter queue.
var queue2 = new Queue(this, "Queue", new QueueProps {
    RedriveAllowPolicy = new RedriveAllowPolicy {
        RedrivePermission = RedrivePermission.DENY_ALL
    }
});
go
var sourceQueue IQueue


// Only the sourceQueue can specify this queue as the dead-letter queue.
queue1 := sqs.NewQueue(this, jsii.String("Queue2"), &QueueProps{
	RedriveAllowPolicy: &RedriveAllowPolicy{
		SourceQueues: []IQueue{
			sourceQueue,
		},
	},
})

// No source queues can specify this queue as the dead-letter queue.
queue2 := sqs.NewQueue(this, jsii.String("Queue"), &QueueProps{
	RedriveAllowPolicy: &RedriveAllowPolicy{
		RedrivePermission: sqs.RedrivePermission_DENY_ALL,
	},
})

Monitoring ​

SQS metrics are available as metric* methods on a queue; metric() returns any metric by name:

ts
const queue = new sqs.Queue(this, 'Queue');

queue.metricApproximateAgeOfOldestMessage().createAlarm(this, 'MessagesTooOld', {
  threshold: Duration.minutes(15).toSeconds(),
  evaluationPeriods: 3,
});
python
queue = sqs.Queue(self, "Queue")

queue.metric_approximate_age_of_oldest_message().create_alarm(self, "MessagesTooOld",
    threshold=Duration.minutes(15).to_seconds(),
    evaluation_periods=3
)
java
Queue queue = new Queue(this, "Queue");

queue.metricApproximateAgeOfOldestMessage().createAlarm(this, "MessagesTooOld", CreateAlarmOptions.builder()
        .threshold(Duration.minutes(15).toSeconds())
        .evaluationPeriods(3)
        .build());
csharp
var queue = new Queue(this, "Queue");

queue.MetricApproximateAgeOfOldestMessage().CreateAlarm(this, "MessagesTooOld", new CreateAlarmOptions {
    Threshold = Duration.Minutes(15).ToSeconds(),
    EvaluationPeriods = 3
});
go
queue := sqs.NewQueue(this, jsii.String("Queue"))

queue.metricApproximateAgeOfOldestMessage().CreateAlarm(this, jsii.String("MessagesTooOld"), &CreateAlarmOptions{
	Threshold: awscdk.Duration_Minutes(jsii.Number(15)).ToSeconds(),
	EvaluationPeriods: jsii.Number(3),
})

metricApproximateNumberOfMessagesOutstanding() returns ApproximateNumberOfMessagesVisible + ApproximateNumberOfMessagesNotVisible as a metric math expression: messages waiting to be picked up, plus messages received but not yet deleted.

Autoscaling consumers on queue depth ​

Scaling a worker fleet on queue depth needs a different metric in each direction:

  • Scale out on ApproximateNumberOfMessagesVisible — work nobody has started yet. An in-flight message is already owned by a consumer, so adding capacity for it produces an idle consumer.
  • Scale in on metricApproximateNumberOfMessagesOutstanding() — everything still owed. Receiving a message moves it from Visible to NotVisible, so a policy watching Visible alone cannot tell a consumer that just picked up work from one that finished it, and can terminate a consumer mid-message. The message reappears only after its visibility timeout, so the longer consumers hold messages, the longer that work stalls.

That means two one-sided policies; the change: 0 step keeps each from acting in the other direction:

ts
declare const service: ecs.FargateService;
const queue = new sqs.Queue(this, 'Queue');

const taskCount = service.autoScaleTaskCount({ minCapacity: 1, maxCapacity: 10 });

taskCount.scaleOnMetric('ScaleOutOnWaitingWork', {
  metric: queue.metricApproximateNumberOfMessagesVisible({ period: Duration.minutes(1) }),
  scalingSteps: [
    { upper: 30, change: 0 },
    { lower: 30, change: +1 },
  ],
  adjustmentType: appscaling.AdjustmentType.CHANGE_IN_CAPACITY,
});

// Remove a task only when nothing is outstanding, so it cannot be holding a message.
taskCount.scaleOnMetric('ScaleInOnOutstandingWork', {
  metric: queue.metricApproximateNumberOfMessagesOutstanding({ period: Duration.minutes(1) }),
  scalingSteps: [
    { upper: 0, change: -1 },
    { lower: 0, change: 0 },
  ],
  adjustmentType: appscaling.AdjustmentType.CHANGE_IN_CAPACITY,
});
python
# service: ecs.FargateService

queue = sqs.Queue(self, "Queue")

task_count = service.auto_scale_task_count(min_capacity=1, max_capacity=10)

task_count.scale_on_metric("ScaleOutOnWaitingWork",
    metric=queue.metric_approximate_number_of_messages_visible(period=Duration.minutes(1)),
    scaling_steps=[appscaling.ScalingInterval(upper=30, change=0), appscaling.ScalingInterval(lower=30, change=+1)
    ],
    adjustment_type=appscaling.AdjustmentType.CHANGE_IN_CAPACITY
)

# Remove a task only when nothing is outstanding, so it cannot be holding a message.
task_count.scale_on_metric("ScaleInOnOutstandingWork",
    metric=queue.metric_approximate_number_of_messages_outstanding(period=Duration.minutes(1)),
    scaling_steps=[appscaling.ScalingInterval(upper=0, change=-1), appscaling.ScalingInterval(lower=0, change=0)
    ],
    adjustment_type=appscaling.AdjustmentType.CHANGE_IN_CAPACITY
)
java
FargateService service;

Queue queue = new Queue(this, "Queue");

ScalableTaskCount taskCount = service.autoScaleTaskCount(EnableScalingProps.builder().minCapacity(1).maxCapacity(10).build());

taskCount.scaleOnMetric("ScaleOutOnWaitingWork", BasicStepScalingPolicyProps.builder()
        .metric(queue.metricApproximateNumberOfMessagesVisible(MetricOptions.builder().period(Duration.minutes(1)).build()))
        .scalingSteps(List.of(ScalingInterval.builder().upper(30).change(0).build(), ScalingInterval.builder().lower(30).change(+1).build()))
        .adjustmentType(AdjustmentType.CHANGE_IN_CAPACITY)
        .build());

// Remove a task only when nothing is outstanding, so it cannot be holding a message.
taskCount.scaleOnMetric("ScaleInOnOutstandingWork", BasicStepScalingPolicyProps.builder()
        .metric(queue.metricApproximateNumberOfMessagesOutstanding(MetricOptions.builder().period(Duration.minutes(1)).build()))
        .scalingSteps(List.of(ScalingInterval.builder().upper(0).change(-1).build(), ScalingInterval.builder().lower(0).change(0).build()))
        .adjustmentType(AdjustmentType.CHANGE_IN_CAPACITY)
        .build());
csharp
FargateService service;

var queue = new Queue(this, "Queue");

var taskCount = service.AutoScaleTaskCount(new EnableScalingProps { MinCapacity = 1, MaxCapacity = 10 });

taskCount.ScaleOnMetric("ScaleOutOnWaitingWork", new BasicStepScalingPolicyProps {
    Metric = queue.MetricApproximateNumberOfMessagesVisible(new MetricOptions { Period = Duration.Minutes(1) }),
    ScalingSteps = new [] { new ScalingInterval { Upper = 30, Change = 0 }, new ScalingInterval { Lower = 30, Change = +1 } },
    AdjustmentType = AdjustmentType.CHANGE_IN_CAPACITY
});

// Remove a task only when nothing is outstanding, so it cannot be holding a message.
taskCount.ScaleOnMetric("ScaleInOnOutstandingWork", new BasicStepScalingPolicyProps {
    Metric = queue.MetricApproximateNumberOfMessagesOutstanding(new MetricOptions { Period = Duration.Minutes(1) }),
    ScalingSteps = new [] { new ScalingInterval { Upper = 0, Change = -1 }, new ScalingInterval { Lower = 0, Change = 0 } },
    AdjustmentType = AdjustmentType.CHANGE_IN_CAPACITY
});
go
var service FargateService

queue := sqs.NewQueue(this, jsii.String("Queue"))

taskCount := service.AutoScaleTaskCount(&EnableScalingProps{
	MinCapacity: jsii.Number(1),
	MaxCapacity: jsii.Number(10),
})

taskCount.ScaleOnMetric(jsii.String("ScaleOutOnWaitingWork"), &BasicStepScalingPolicyProps{
	Metric: queue.metricApproximateNumberOfMessagesVisible(&MetricOptions{
		Period: awscdk.Duration_Minutes(jsii.Number(1)),
	}),
	ScalingSteps: []ScalingInterval{
		&ScalingInterval{
			Upper: jsii.Number(30),
			Change: jsii.Number(0),
		},
		&ScalingInterval{
			Lower: jsii.Number(30),
			Change: +jsii.Number(1),
		},
	},
	AdjustmentType: appscaling.AdjustmentType_CHANGE_IN_CAPACITY,
})

// Remove a task only when nothing is outstanding, so it cannot be holding a message.
taskCount.ScaleOnMetric(jsii.String("ScaleInOnOutstandingWork"), &BasicStepScalingPolicyProps{
	Metric: queue.MetricApproximateNumberOfMessagesOutstanding(&MetricOptions{
		Period: awscdk.Duration_*Minutes(jsii.Number(1)),
	}),
	ScalingSteps: []ScalingInterval{
		&ScalingInterval{
			Upper: jsii.Number(0),
			Change: -jsii.Number(1),
		},
		&ScalingInterval{
			Lower: jsii.Number(0),
			Change: jsii.Number(0),
		},
	},
	AdjustmentType: appscaling.AdjustmentType_CHANGE_IN_CAPACITY,
})

Caveats:

  • Target tracking rejects this metric. It accepts only direct metrics, so scaleToTrackCustomMetric() throws Only direct metrics are supported for Target Tracking (aws-cdk#20659).
  • ApproximateNumberOfMessagesNotVisible can briefly report non-zero on an empty queue if an SQS storage server is unavailable. Evaluate several consecutive datapoints, especially when scaling in to zero.
  • Neither term counts delayed messages. Add metricApproximateNumberOfMessagesDelayed() if you use delay queues or DelaySeconds.

Types ​

NameKindSummary
QueueConstruct (L2)A new Amazon SQS queue.
QueueBaseConstruct (L2)Reference to a new or existing Amazon SQS queue.
QueuePolicyConstruct (L2)The policy for an SQS Queue.
CfnQueueConstruct (L1)The AWS::SQS::Queue resource creates an Amazon SQS standard or FIFO queue.
CfnQueueInlinePolicyConstruct (L1)The AWS::SQS::QueueInlinePolicy resource associates one Amazon SQS queue with one policy.
CfnQueuePolicyConstruct (L1)The AWS::SQS::QueuePolicy type applies a policy to Amazon SQS queues.
CfnQueueInlinePolicyPropsStructProperties for defining a CfnQueueInlinePolicy.
CfnQueuePolicyPropsStructProperties for defining a CfnQueuePolicy.
CfnQueuePropsStructProperties for defining a CfnQueue.
DeadLetterQueueStructDead letter queue settings.
DeduplicationScopeEnumWhat kind of deduplication scope to apply.
FifoThroughputLimitEnumWhether the FIFO queue throughput quota applies to the entire queue or per message group.
IQueueInterfaceRepresents an SQS queue.
QueueAttributesStructReference to a queue.
QueueEncryptionEnumWhat kind of encryption to apply to this queue.
QueueGrantsFacadeCollection of grant methods for a IQueueRef.
QueuePolicyPropsStructProperties to associate SQS queues with a policy.
QueuePropsStructProperties for creating a new Queue.
RedriveAllowPolicyStructPermission settings for the dead letter source queue.
RedrivePermissionEnumThe permission type that defines which source queues can specify the current queue as the dead-letter queue.