Packages
| Package | Service | Purpose |
|---|---|---|
@aws-sdk/client-sns | Amazon Simple Notification Service | Publish messages to topics; fan-out to multiple subscribers |
@aws-sdk/client-sqs | Amazon Simple Queue Service | Send and receive messages via durable queues |
Installation
npm install @aws-sdk/client-sns @aws-sdk/client-sqs
Creating the clients
import { SNSClient } from "@aws-sdk/client-sns";
import { SQSClient } from "@aws-sdk/client-sqs";
const snsClient = new SNSClient({ region: "us-east-1" });
const sqsClient = new SQSClient({ region: "us-east-1" });
- SNS
- SQS
SNS commands
PublishCommand — publish a message to a topic
PublishCommand — publish a message to a topic
import { SNSClient, PublishCommand } from "@aws-sdk/client-sns";
const client = new SNSClient({ region: "us-east-1" });
const response = await client.send(
new PublishCommand({
TopicArn: "arn:aws:sns:us-east-1:123456789012:my-topic",
Message: "Hello from SNS!",
Subject: "Order confirmation",
// Optional: structured JSON for per-protocol messages
// MessageStructure: "json",
// Message: JSON.stringify({
// default: "Hello!",
// email: "Hello from email",
// sqs: JSON.stringify({ event: "order.created" }),
// }),
})
);
console.log(response.MessageId);
TopicArn with TargetArn or PhoneNumber.CreateTopicCommand — create a topic
CreateTopicCommand — create a topic
import { SNSClient, CreateTopicCommand } from "@aws-sdk/client-sns";
const client = new SNSClient({ region: "us-east-1" });
const response = await client.send(
new CreateTopicCommand({
Name: "order-events",
// Optional: create a FIFO topic
// Name: "order-events.fifo",
// Attributes: {
// FifoTopic: "true",
// ContentBasedDeduplication: "true",
// },
})
);
console.log(response.TopicArn);
// "arn:aws:sns:us-east-1:123456789012:order-events"
CreateTopicCommand is idempotent — calling it again with the same name returns the existing topic ARN.SubscribeCommand — subscribe an endpoint to a topic
SubscribeCommand — subscribe an endpoint to a topic
import { SNSClient, SubscribeCommand } from "@aws-sdk/client-sns";
const client = new SNSClient({ region: "us-east-1" });
// Subscribe an SQS queue
const response = await client.send(
new SubscribeCommand({
TopicArn: "arn:aws:sns:us-east-1:123456789012:order-events",
Protocol: "sqs",
Endpoint: "arn:aws:sqs:us-east-1:123456789012:order-processing-queue",
Attributes: {
// Confirm the subscription immediately (requires appropriate IAM policy)
RawMessageDelivery: "true",
},
})
);
// Subscribe an HTTPS endpoint
await client.send(
new SubscribeCommand({
TopicArn: "arn:aws:sns:us-east-1:123456789012:order-events",
Protocol: "https",
Endpoint: "https://example.com/webhooks/sns",
})
);
// Subscribe an email address
await client.send(
new SubscribeCommand({
TopicArn: "arn:aws:sns:us-east-1:123456789012:order-events",
Protocol: "email",
Endpoint: "alerts@example.com",
})
);
console.log(response.SubscriptionArn);
sqs, https, http, email, email-json, sms, lambda, and application.ListTopicsCommand — list topics
ListTopicsCommand — list topics
import { SNSClient, ListTopicsCommand } from "@aws-sdk/client-sns";
const client = new SNSClient({ region: "us-east-1" });
const response = await client.send(new ListTopicsCommand({}));
for (const topic of response.Topics ?? []) {
console.log(topic.TopicArn);
}
// Paginate if NextToken is present
if (response.NextToken) {
const nextPage = await client.send(
new ListTopicsCommand({ NextToken: response.NextToken })
);
console.log(nextPage.Topics);
}
SQS commands
SendMessageCommand — send a message
SendMessageCommand — send a message
import { SQSClient, SendMessageCommand } from "@aws-sdk/client-sqs";
const client = new SQSClient({ region: "us-east-1" });
const response = await client.send(
new SendMessageCommand({
QueueUrl:
"https://sqs.us-east-1.amazonaws.com/123456789012/my-queue",
MessageBody: JSON.stringify({ event: "order.created", orderId: "order-123" }),
DelaySeconds: 0, // Delay before the message becomes visible (0-900 seconds)
MessageAttributes: {
EventType: {
DataType: "String",
StringValue: "order.created",
},
},
})
);
console.log(response.MessageId);
ReceiveMessageCommand — poll for messages
ReceiveMessageCommand — poll for messages
import { SQSClient, ReceiveMessageCommand } from "@aws-sdk/client-sqs";
const client = new SQSClient({ region: "us-east-1" });
const response = await client.send(
new ReceiveMessageCommand({
QueueUrl:
"https://sqs.us-east-1.amazonaws.com/123456789012/my-queue",
MaxNumberOfMessages: 10, // 1-10
WaitTimeSeconds: 20, // Long polling — waits up to 20 seconds for messages
VisibilityTimeout: 30, // Seconds the message is hidden after being received
MessageAttributeNames: ["All"],
AttributeNames: ["All"],
})
);
for (const message of response.Messages ?? []) {
console.log({
messageId: message.MessageId,
body: message.Body,
receiptHandle: message.ReceiptHandle, // Required to delete the message
});
}
Always use
WaitTimeSeconds: 20 (long polling). Short polling (WaitTimeSeconds: 0) returns immediately even when the queue is empty, leading to higher costs and unnecessary API calls.DeleteMessageCommand — delete a processed message
DeleteMessageCommand — delete a processed message
After successfully processing a message, delete it to prevent redelivery:If you do not delete a message within its
import {
SQSClient,
ReceiveMessageCommand,
DeleteMessageCommand,
} from "@aws-sdk/client-sqs";
const client = new SQSClient({ region: "us-east-1" });
const queueUrl =
"https://sqs.us-east-1.amazonaws.com/123456789012/my-queue";
const { Messages } = await client.send(
new ReceiveMessageCommand({
QueueUrl: queueUrl,
MaxNumberOfMessages: 1,
WaitTimeSeconds: 20,
})
);
if (Messages && Messages.length > 0) {
const message = Messages[0];
// Process the message
console.log("Processing:", message.Body);
// Delete after successful processing
await client.send(
new DeleteMessageCommand({
QueueUrl: queueUrl,
ReceiptHandle: message.ReceiptHandle!,
})
);
}
VisibilityTimeout, SQS makes it visible again and it will be redelivered.CreateQueueCommand — create a queue
CreateQueueCommand — create a queue
import { SQSClient, CreateQueueCommand } from "@aws-sdk/client-sqs";
const client = new SQSClient({ region: "us-east-1" });
// Standard queue
const response = await client.send(
new CreateQueueCommand({
QueueName: "my-queue",
Attributes: {
VisibilityTimeout: "30",
MessageRetentionPeriod: "86400", // 1 day in seconds
ReceiveMessageWaitTimeSeconds: "20", // Enable long polling by default
},
})
);
// FIFO queue (name must end in .fifo)
const fifoResponse = await client.send(
new CreateQueueCommand({
QueueName: "my-queue.fifo",
Attributes: {
FifoQueue: "true",
ContentBasedDeduplication: "true",
},
})
);
console.log(response.QueueUrl);
CreateQueueCommand is idempotent when called with the same name and attributes.GetQueueUrlCommand — get queue URL by name
GetQueueUrlCommand — get queue URL by name
import { SQSClient, GetQueueUrlCommand } from "@aws-sdk/client-sqs";
const client = new SQSClient({ region: "us-east-1" });
const response = await client.send(
new GetQueueUrlCommand({
QueueName: "my-queue",
// Optional: owner's AWS account ID for cross-account queues
// QueueOwnerAWSAccountId: "987654321098",
})
);
console.log(response.QueueUrl);
// "https://sqs.us-east-1.amazonaws.com/123456789012/my-queue"
Fan-out pattern: SNS to SQS
A common pattern is to publish a single SNS message and deliver it to multiple SQS queues, decoupling producers from consumers:import { SNSClient, PublishCommand } from "@aws-sdk/client-sns";
const snsClient = new SNSClient({ region: "us-east-1" });
// Publish once — SNS fans out to all subscribed SQS queues
await snsClient.send(
new PublishCommand({
TopicArn: "arn:aws:sns:us-east-1:123456789012:order-events",
Message: JSON.stringify({
event: "order.created",
orderId: "order-789",
total: 99.99,
}),
})
);