SQS

Lightweight, dependency-free fake of AWS SQS that speaks the real modern SQS JSON wire protocol (AWS JSON 1.0, query-compatible), so application code using @aws-sdk/client-sqs can run against it with zero cost and zero side effects.

KeyValue
Port4568
ProtocolAWS SQS JSON (AWS JSON 1.0, awsQueryCompatible) over HTTP
Compatible client@aws-sdk/client-sqs (v3)
Size~80 KB
Startup< 100ms
StateIn-memory, ephemeral, resettable

Quick Start

Start the server:

import { SqsServer } from "./services/sqs/src/server.js";

const server = new SqsServer(4568);
await server.start();
// ... use it ...
await server.stop();

Connect with the real AWS SDK client:

import {
  SQSClient,
  CreateQueueCommand,
  SendMessageCommand,
  ReceiveMessageCommand,
  DeleteMessageCommand,
} from "@aws-sdk/client-sqs";

const sqs = new SQSClient({
  region: "us-east-1",
  endpoint: "http://127.0.0.1:4568",
  credentials: { accessKeyId: "parlel", secretAccessKey: "parlel" },
});

const { QueueUrl } = await sqs.send(new CreateQueueCommand({ QueueName: "jobs" }));

await sqs.send(new SendMessageCommand({ QueueUrl, MessageBody: "hello world" }));

const { Messages } = await sqs.send(
  new ReceiveMessageCommand({ QueueUrl, MaxNumberOfMessages: 1 }),
);
console.log(Messages[0].Body); // "hello world"

await sqs.send(
  new DeleteMessageCommand({ QueueUrl, ReceiptHandle: Messages[0].ReceiptHandle }),
);

Queue URLs

Created queues return a URL of the form http://127.0.0.1:4568/{accountId}/{queueName} (default account id 000000000000). The SDK's useQueueUrlAsEndpoint behavior uses the URL's origin as the request endpoint, so the host/port in the URL must match the running fake — which it does automatically. Bare queue names are also accepted wherever a QueueUrl is expected (the last path segment is used as the queue name).

Wire protocol

Authentication

SigV4 signatures are accepted but not verified (any credentials work). This matches LocalStack-style local development.

MD5 checksums

The real @aws-sdk/client-sqs validates MD5OfMessageBody, MD5OfBody, and MD5OfMessageAttributes locally after each call. This fake computes each of those exactly the way AWS does (including the canonical length-prefixed message-attribute digest), so the SDK's built-in validation passes.

Implemented Operations

All 23 operations exposed by @aws-sdk/client-sqs are implemented and tested.

Queue lifecycle

Queue attributes

Messaging

Tags

Permissions

Dead-letter queues & message move tasks

Behavioral notes

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatusNotes
Standard queues✅ Supported
FIFO queues + dedup + ordering✅ Supported5-minute dedup window
Message attributes + MD5✅ SupportedAWS-canonical MD5 digest
Message system attributes✅ Supportede.g. AWSTraceHeader
Visibility timeout / delay✅ Supportedreal timers, auto re-visibility
Batch send/delete/visibility✅ Supportedpartial-failure semantics
Tags✅ Supported
Permissions (Add/Remove)✅ Supportedstored, not enforced
Dead-letter source listing✅ Supportedderived from RedrivePolicy
Message move tasks (redrive)✅ Supportedsynchronous completion
Pagination✅ SupportedListQueues MaxResults/NextToken
Long polling (WaitTimeSeconds)⚠️ Accepted, returns immediatelyno blocking wait
Server-side encryption / KMS⚠️ Attributes stored onlyno real crypto
SigV4 signature verification✓ By design — Structurally faithful tokens; cryptographic verification is skipped for local use
Actual message retention expiry✓ By design — Intentional for a local, zero-cost test emulator
Redrive maxReceiveCount auto-DLQ✓ By design — Not enforced

Error codes

Errors are returned as { "__type": "<Code>", "message": "..." } with the x-amzn-query-error: <Code>;<Fault> header. The SDK surfaces them as typed exceptions (the modeled name may differ from the wire code, e.g. the wire code AWS.SimpleQueueService.NonExistentQueue surfaces as QueueDoesNotExist).

Wire codeHTTPWhen
AWS.SimpleQueueService.NonExistentQueue400Queue URL/name does not exist (→ QueueDoesNotExist)
QueueAlreadyExists400Re-create with conflicting attributes (→ QueueNameExists)
InvalidParameterValue400Bad queue name, FIFO mismatch, oversized body, bad visibility, etc.
InvalidAttributeName400Unknown attribute passed to SetQueueAttributes
MissingParameter400Required parameter omitted
ReceiptHandleIsInvalid400Malformed receipt handle on delete
AWS.SimpleQueueService.MessageNotInflight400ChangeMessageVisibility on a non-inflight message
AWS.SimpleQueueService.EmptyBatchRequest400Batch request with no entries
AWS.SimpleQueueService.TooManyEntriesInBatchRequest400More than 10 batch entries
AWS.SimpleQueueService.BatchEntryIdsNotDistinct400Duplicate Id within a batch
ResourceNotFoundException404Move task / move-task source not found
InvalidAction400Unknown X-Amz-Target operation

Resetting state

State is in-memory and ephemeral. Reset it programmatically or over HTTP:

server.reset();                                   // in-process
await fetch("http://127.0.0.1:4568/_parlel/reset", { method: "POST" }); // over HTTP

Health check

GET http://127.0.0.1:4568/_parlel/health
→ { "status": "ok", "service": "sqs", "queues": <n> }
<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

AWS_ACCESS_KEY_ID=parlel
AWS_SECRET_ACCESS_KEY=parlel
AWS_REGION=us-east-1
AWS_ENDPOINT_URL_SQS=http://parlel-bridge:4568
AWS_ENDPOINT_URL=http://parlel-bridge:4568
<!-- parlel:testenv:end -->