Skip to main content

Overview

The SQSQueue construct creates an Amazon SQS queue with an optional dead-letter queue, FIFO ordering, encryption, and a DLQ-depth CloudWatch alarm. Use it to decouple producers and consumers in event-driven architectures. Every queue is created with enforceSSL: true, so the queue policy denies any request that does not arrive over TLS.

Import

Add a queue from the CLI

fjall add messaging writes the queue into your application’s infrastructure.ts:
The codemod always emits type: "queue", so the statement it writes is a valid MessagingFactory call. Modify an existing queue by name:
The CLI property vocabulary is narrower than the construct’s, and one flag is spelled differently: Every other property in the tables below is authored by hand in infrastructure.ts.

Using the Messaging Factory

Inside infrastructure.ts, add SQS through the MessagingFactory:

Direct construct usage

Properties

removalPolicy defaults to "DESTROY", not "RETAIN". Deleting the stack deletes the queue, its in-flight messages, and the auto-created dead-letter queue, which tracks the same policy. A queue is treated as a transient work medium whose contents regenerate from a source of truth held elsewhere. Pass removalPolicy: "RETAIN" for a queue whose contents are irreplaceable.
kmsKeyArn is present on the props type but the construct does not read it. Setting encryption: "SSE_KMS" maps to CDK’s QueueEncryption.KMS, which provisions a new CDK-managed KMS key rather than the key you name. Use the default "SSE_SQS" unless you have a specific reason to hold a separate key.
A value of 0 for visibilityTimeout, receiveMessageWaitTime or deliveryDelay is treated as unset, and the AWS default applies. To turn long polling off explicitly, leave receiveMessageWaitTime out.

Factory prop differences

MessagingFactory.build accepts IQueueProps, which is a subset of the construct props with one widened field: The factory also validates ranges eagerly and throws on an out-of-range visibilityTimeout, messageRetentionPeriod, deliveryDelay, receiveMessageWaitTime or maxMessageSize, and warns when FIFO-only options are set on a standard queue.

Dead-letter queue behaviour

When deadLetterQueue.enabled is true and you do not supply your own queue, Fjall creates a companion DLQ alongside the main queue: Pair the DLQ with alertsTopic to get a CloudWatch alarm on DLQ depth. The alarm fires on the maximum of ApproximateNumberOfMessagesVisible over one evaluation period, with a default threshold of 0, so any dead-lettered message pages. Override it with alarms: { dlqDepthThreshold: 5 }, or disable it with alarms: false. A bring-your-own DLQ passed as deadLetterQueue.queue is never alarmed here. Its owner wires the alarms, which keeps a shared DLQ from collecting one duplicate alarm per referencing queue.

Queue-policy limits

The queue’s single resource policy holds the TLS-only statement Fjall adds plus every grant to a service that pushes to the queue: each EventBridge rule, each SNS subscription, each S3 notification. None of those reaches a queue through an IAM role, so the resource policy is their only grant. A grant to a role, such as tasks.grantSendMessages(apiService) or the execution role addSqsEventSource grants a polling Lambda, lands on that role’s own policy and costs nothing here. SQS caps the queue policy at 20 statements and 8,192 bytes, and refuses the whole policy past either. From fjall 38 SQSQueue checks the policy when the application synthesises, so an over-budget queue is refused before the deploy instead of rolling the stack back mid-deploy. The check covers the queue and the dead-letter queue Fjall creates. A dead-letter queue you pass as deadLetterQueue.queue is not checked here. It is checked only when it is itself a Fjall SQSQueue, by that construct. Each refusal names the queue’s construct path and tells you to split the grants across queues. An EventBridge rule costs its ARN inside a shared statement rather than a statement of its own, so rules exhaust the byte budget long before the statement count. That byte count is an upper bound. An ARN CloudFormation has not created yet is sized at the longest its partition, region, account and name can be, so the refusal can arrive a few grants before SQS’s own would. The thresholds above do not apply to a queue created with encryption: "SSE_KMS". Its delivery grant names the account rather than each rule, so one statement covers however many rules deliver to it. As a rule’s dead-letter queue it still shares the dead-letter statement like any other queue. A reference the check cannot size counts at CDK’s own ARN estimate of 150 bytes, and the refusal says how many references that applied to. Lower the estimate when those ARNs are shorter, by adding this one key to the context block already in the application’s cdk.json. Leave the rest of that block in place, including @aws-cdk/aws-iam:minimizePolicies:
cdk.json
The first deploy on fjall 38 rewrites each affected AWS::SQS::QueuePolicy in place, including a queue with a single rule. No queue or rule is replaced, and the same rules are granted before and after. Regenerate any snapshot that reads a queue policy, and see the changelog for the migration.

Methods

Both the construct and the factory wrapper expose these: The factory wrapper adds the IQueueMessaging interface names:

Examples

Standard queue with a DLQ

DLQ alarm on a shared topic

FIFO queue

FIFO queues preserve message order and deduplicate within a five-minute window:

Long polling

Long polling cuts empty receive responses and the API calls they cost:

Retained queue

Connecting to Lambda

addSqsEventSource takes a CDK IQueue, so pass the underlying queue rather than the Fjall wrapper:
The Lambda polls the queue and deletes messages it processes. Set visibilityTimeout on the queue to at least the function’s timeout, otherwise a slow invocation lets the same message be redelivered while it is still in flight.

CloudFormation Outputs

Output keys are built from the construct id converted to PascalCase, so new SQSQueue(scope, "order-events", {}) produces OrderEventsQueueUrl. A bring-your-own DLQ emits no DLQ outputs, since the queue is owned by another stack.

Next Steps

Messaging Factory

Create queues, topics, and event buses through one factory

Lambda Function

Process queue messages with Lambda

SNS Topic

Fan out one publish to many subscribers

EventBridge

Route events with rules and schedules