No Bottlenecks. Just SQS.

Kartik MehtaKartik Mehta
8 min read

When building modern applications, we often encounter a dilemma:

  • Should we process tasks immediately within the API call?

  • Or offload them and return quickly?

As your application scales, tasks like sending emails, processing payments, resizing images, or syncing data can introduce latency and risk. That’s where queues shine — by allowing systems to decouple work and handle it asynchronously.

What is a Queue in Software?

A queue is a data structure that follows FIFO (First-In, First-Out) — the first item added is the first to be removed.

In distributed systems:

  • A Producer adds jobs/tasks/messages to the queue.

  • One or more Consumers process those messages independently.

Distributed Messaging Queue: Everything You Need to Know About | by Arslan  Ahmad | Geek Culture | Medium

This separation improves responsiveness, fault tolerance, and scalability.

Why Queues Are Critical in Modern Architectures

  1. Decoupling Components: Queues allow services to operate independently. (Ex, If the email service is slow, the signup API still works.)

  2. Improved Resilience: If a consumer crashes, the queue persists tasks until it's back.

  3. Auto-Scaling: You can increase consumers to process high loads dynamically.

  4. Retry & Error Handling: Failed jobs can be retried or moved to a Dead Letter Queue (DLQ).

  5. Rate Limiting at Scale: You can control how fast background jobs are processed, avoiding downstream overload.

Why Choose AWS SQS as Your Queueing System?

Amazon SQS stands out as a robust, fully managed message queuing service that eliminates the overhead of managing message brokers and scaling infrastructure manually. Designed for durability, flexibility, and performance, SQS offers features that make it ideal for both startups and enterprise-grade applications. Its native integration with the AWS ecosystem (like Lambda, SNS, and CloudWatch) allows for powerful event-driven architectures. You don’t have to worry about provisioning servers or handling failover — SQS scales automatically with your workload.

Features like visibility timeouts, dead-letter queues, long polling, and encryption make it a secure and intelligent choice when building modern, asynchronous backend systems. Amazon SQS (Simple Queue Service) is a fully managed message queuing service that:

  • Scales automatically

  • Offers at-least-once delivery

  • Works seamlessly with other AWS services

Diagram detailing how SQS works.

Amazon SQS allows producers to send messages to a queue. Messages are then stored in an SQS Queue. When consumers are ready to process new messages they poll them from the queue. Applications, micro-services, and multiple AWS services can take the role of producers or consumers.

Benefits and features of SQS

  1. Highly scalable Standard and FIFO queues: Queues scale elastically with your application. Nearly unlimited throughput and no limit to the number of messages per queue in Standard queues. First-In-First-Out delivery and exactly once processing in FIFO queues.

  2. Durability and availability: Your queues are distributed on multiple servers. Redundant infrastructure provides highly concurrent access to messages.

  3. Security: Protection in transit and at rest. Transmit sensitive data in encrypted queues. Send messages in a Virtual Private Cloud.

  4. Batching: Send, receive, or delete messages in batches of up to 10 messages or 256KB to save costs.

What We're Building Today

We're walking through a real-world implementation of an event-driven Node.js system using Amazon SQS. You’ll learn how we decoupled a user signup workflow by pushing email notifications to a queue — making our backend more scalable, performant, and resilient.

This guide is based on the project:

This repo demonstrates a simple and scalable system where user registration triggers an asynchronous welcome email using AWS SQS and Nodemailer.

We'll explore:

  • A full walkthrough of the codebase structure

  • How to set up SQS in your AWS account

  • How to test your implementation under load

Let's dive into the power of queues and how SQS unlocks a world of scalable, asynchronous architectures.

The Plot

Sending welcome emails directly during user registration can slow down your app, especially under load. A better approach is to offload the email task to a background worker using AWS SQS — giving your API a major performance boost.

1. Project Structure

.
├── config/                   # MongoDB connection.
│   └── db.js
├── controllers/
│   └── authController.js     # Signup & Signin with SQS enqueue.
├── middleware/
│   └── rateLimitMiddleware.js
├── models/
│   └── User.js               # Mongoose schema.
├── routes/
│   └── authRoutes.js
├── services/
│   ├── emailService.js       # (Not shown here) Worker to send actual emails.
│   └── sqsService.js         # AWS SQS integration (Producer)
├── utils/
│   └── validateInput.js
├── worker/
│   └── emailWorker.js        # (Consumer) Polls SQS and sends emails.
├── .env                      # Environment variables.
├── server.js                 # Entry point.
└── package.json

This structure separates concerns: auth logic, SQS handling, email delivery, and background processing — all decoupled and scalable. I recommend readers check this out, as the code details are not discussed, the blog is focused on SQS.

2. Environment Variables

Check out the sample .env file to see how the environment variables are structured.

# This file contains all the environment variables that are required by the application.
PORT=5001
JWT_SECRET=kartikmehta
MONGO_URI=mongodb://localhost:27017

# Email
EMAIL_USER=
EMAIL_PASS=

# AWS
AWS_REGION=ap-south-1
AWS_SQS_QUEUE_URL=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

This is how you can set up EMAIL_USER and EMAIL_PASS.

Setting Up AWS SQS

Create the SQS Queue

  1. Go to https://console.aws.amazon.com/sqs

  1. Click Create Queue

  2. Choose Standard

  3. Name it email-queue

  4. Leave defaults and create.

The SQS Queue URI can be obtained from the following location:

Create IAM Access Keys

  1. Go to AWS Console > IAM.

  1. On the left-hand side, under Access Management, click on Users. This is where you can create users and generate their access keys and secrets. Click Create user.

  2. Enter a username and click Next to proceed.

  3. In the Permissions section, select Attach policies directly.

    Scroll down to view the available policies. We only need to attach two policies:

    • AmazonSQSFullAccess (for now)
  4. Click Create user. You have successfully created the user.

  5. Now, to generate the Access Key ID and Secret Access Key for this user, select the user you just created. Navigate to the Security Credentials tab.

  1. Scroll down to the Access Keys section and click Create access key.

  2. Select Command Line Interface (CLI) as the use case, acknowledge the warning at the bottom, and click Next to proceed.

  1. Click Create access key. You can see your Access Key ID and Secret Access Key.

Now we have all the environment keys needed to run this project. Let’s go through the code to understand what’s being done.

Before vs After AWS SQS Integration

Let’s look at signup logic before and after integrating SQS.

Before (Synchronous Email Sending)

const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({ /* config */ });

const registerUser = async (req, res) => {
  const { name, email, password } = req.body;
  const user = await User.create({ name, email, password });

  await transporter.sendMail({
    from: 'support@example.com',
    to: email,
    subject: 'Welcome!',
    html: `<h1>Hi ${name}</h1>`,
  });

  res.status(201).json({ user });
};

Problems:

  • Email sending delays the response

  • If SMTP fails, user signup breaks

  • Harder to retry or monitor delivery failures

After (Async SQS Job Enqueue)

// controllers/authController.js
const registerUser = async (req, res) => {
  const { name, email, password } = req.body;
  const user = await User.create({ name, email, password });

  // Send to queue instead of SMTP directly
  await sendToQueue({ email: user.email, name: user.name });

  res.status(201).json({ user });
};

and

const processMessages = async () => {
  const params = { QueueUrl: QUEUE_URL, MaxNumberOfMessages: 10 };

  const data = await sqs.receiveMessage(params).promise();
  if (data.Messages) {
    for (const message of data.Messages) {
      const { email, name } = JSON.parse(message.Body);
      await sendWelcomeEmail(email, name);
      await sqs.deleteMessage({ QueueUrl: QUEUE_URL, ReceiptHandle: message.ReceiptHandle }).promise();
      console.log(`Message processed: ${message.Body}`);
    }
  }
};

// code...

setInterval(processMessages, 5000);

Result:

  • Signup completes instantly

  • Email handled out-of-band

  • You can now add metrics, retries, and even scale with AWS Lambda

BenefitExplanation
Fast API ResponsesSignup API doesn’t wait for email to be sent
Reliable Job HandlingEmails won’t be lost on server crash
Retry SupportAWS SQS allows retry attempts or dead letter queue
Async ScalabilityWorkers scale separately — 1 or 100 workers
Better User ExperienceEmails sent quickly in parallel with user interaction
Clear Audit TrailLog every queued job for debugging or tracking
Language/Platform AgnosticMultiple services in different stacks can share the same queue

TL;DR: Why This Pattern Rocks

  • The frontend and API remain lightweight and blazing fast

  • Failures in your SMTP provider won’t break user signups

  • Your system is now ready for scale, reliability, and observability

Conclusion

In this tutorial, we implemented AWS SQS to offload email sending from the signup flow, improving speed and reliability. While this was a basic use case, SQS can power much more—like async tasks for report generation, payment processing, syncing services, or triggering workflows. With built-in features like retry policies, dead letter queues, visibility timeouts, and high throughput, AWS SQS ensures fault-tolerant, scalable job handling. By decoupling time-consuming operations from the main app, you keep user interactions fast and systems clean. Queues aren't just for email—they're essential for building modern, event-driven, production-grade backend architecture.

Time to offload the heavy lifting.

If you ever need help or just want to chat, DM me on Twitter / X or LinkedIn.

Kartik Mehta

X / LinkedIn

11
Subscribe to my newsletter

Read articles from Kartik Mehta directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kartik Mehta
Kartik Mehta

A code-dependent life form.