Skip to main content
Amazon SQS is an alternative queue provider: fully managed by AWS, no Redis required, and emulated locally via Localstack.

Why

SQS is the right choice when you want a fully managed, serverless queue with no Redis dependency in production. It scales automatically, integrates natively with the rest of your AWS infrastructure, and removes the operational burden of managing a Redis cluster. Locally it runs through Localstack, so the dev loop stays self-contained inside Docker.

Setup

  1. In apps/backend/package.json, add "tooling-queue-sqs": "workspace:*" under dependencies and remove any other queue adapter package.
  2. Run make pnpm-lockfile-update then make pnpm-install.
  3. In development.ts, production.ts, and test.ts, set tools.queue:
    queue: {
      client: MQType.SQS,
      region: process.env.AWS_REGION,
      endpoint: process.env.SQS_ENDPOINT, // omit in production
      accessKeyId: process.env.AWS_ACCESS_KEY_ID,
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
      queues: [
        {
          name: QueueName.YOUR_QUEUE,
          maxRetries: 3,
          maxMessages: 10,
          retryDelay: 1000,
          errorRetryDelaySeconds: 60,
          dlq: { name: QueueName.YOUR_QUEUE_DLQ, maxMessages: 10 },
        },
      ],
    }
    
  4. In compose.yml, add Localstack and optionally SQS Admin, and wire backend and consumer to start after Localstack is healthy. Add an init container that creates your queues before the backend starts:
    localstack:
      image: localstack/localstack:latest
      environment:
        - SERVICES=sqs
        - DEFAULT_REGION=${AWS_REGION:-us-east-1}
      ports:
        - "4566:4566"
      healthcheck:
        test: ["CMD", "curl", "-sf", "http://localhost:4566/_localstack/health"]
        interval: 5s
        timeout: 5s
        retries: 10
    
    sqs-init:
      image: localstack/localstack:latest
      entrypoint: ["sh", "-c"]
      command:
        - |
          awslocal --endpoint-url=http://localstack:4566 sqs create-queue --queue-name YOUR_QUEUE
          awslocal --endpoint-url=http://localstack:4566 sqs create-queue --queue-name YOUR_QUEUE_DLQ
      depends_on:
        localstack:
          condition: service_healthy
      restart: "no"
    
  5. In .env.development, uncomment and set the SQS vars — placeholder values work for Localstack:
    SQS_ENDPOINT=http://localstack:4566
    AWS_REGION=us-east-1
    AWS_ACCESS_KEY_ID=test
    AWS_SECRET_ACCESS_KEY=test
    
  6. Run make test module=tooling-queue-sqs and make test module=backend.

Local observability

Localstack exposes its health and queue state at http://localhost:4566/_localstack/health. For a full queue UI locally, add the sqs-admin service to compose.yml (port 3999) pointed at http://localstack:4566.
Bull Board (port 3998) does not show SQS traffic — it reads Redis only. If Bull Board is still in your Compose file from a previous BullMQ setup, it will appear empty and can be removed.

Adding a new queue

  1. Add the queue name and its DLQ to the QueueName enum in apps/backend/src/utilities/queue.ts.
  2. Add a matching config block under tools.queue.queues in each env config file — copy an existing entry and adjust the name and retry settings.
  3. Add the awslocal sqs create-queue call for both the queue and DLQ to your sqs-init container in compose.yml — SQS does not auto-create queues.
  4. Add the consumer to apps/backend/src/tools/queue/consumerRegistry.ts. Skip this if you only need a producer.
  5. Run make test module=backend.

Gotchas

  • SQS queues must be created before the consumer starts. If sqs-init hasn’t run yet, the consumer will fail silently on startup.
  • Never commit real AWS credentials in .env.development — the placeholder values (test / test) are intentional for Localstack and safe to commit.
  • SQS_ENDPOINT must be omitted (or left unset) in production config. Pointing it at Localstack in production will silently swallow all messages.
  • Never add @aws-sdk/client-sqs directly to apps/backend/package.json — it is a transitive dependency of tooling-queue-sqs and should stay that way.

What’s next?

  • BullMQ — default Redis-backed provider with Bull Board.
  • Configuration — switching pluggable tool implementations.
  • Tooling system — how loaders and workspace packages fit together.