Azure Queue Storage

Lightweight, dependency-free fake of Azure Queue Storage that speaks the real Azure Queue REST API (XML wire protocol + x-ms-* headers), so application code using @azure/storage-queue can run against it with zero cost and zero side effects.

KeyValue
Port4593
ProtocolAzure Queue Storage REST API (HTTP + XML)
Compatible client@azure/storage-queue (v12)
API version2025-05-05
Size~64 KB
Startup< 100ms
StateIn-memory, ephemeral, resettable

Quick Start

Start the server:

import { AzurequeueServer } from "./services/azurequeue/src/server.js";

const server = new AzurequeueServer(4593);
await server.start();
// ... use it ...
await server.stop();

Connect with the real Azure SDK client. The fake uses path-style addressing (like Azurite), so the queue endpoint always includes the account name:

import { QueueServiceClient, StorageSharedKeyCredential } from "@azure/storage-queue";

const account = "devstoreaccount1";
const key =
  "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";

const credential = new StorageSharedKeyCredential(account, key);
const svc = new QueueServiceClient(
  `http://127.0.0.1:4593/${account}`,
  credential,
);

const queue = svc.getQueueClient("my-queue");
await queue.create();

// Send a message.
const sent = await queue.sendMessage("hello parlel");

// Receive (dequeue) it — becomes invisible for the visibility timeout.
const recv = await queue.receiveMessages();
const msg = recv.receivedMessageItems[0];
// msg.messageText -> "hello parlel"

// Delete it once processed.
await queue.deleteMessage(msg.messageId, msg.popReceipt);

You can also connect via a connection string:

const conn =
  "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;" +
  "AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;" +
  "QueueEndpoint=http://127.0.0.1:4593/devstoreaccount1;";

const svc = QueueServiceClient.fromConnectionString(conn);

URL Shape

http://127.0.0.1:4593/<account>/<queue>?<comp>...                 # queue-level
http://127.0.0.1:4593/<account>/<queue>/messages?...              # messages-level
http://127.0.0.1:4593/<account>/<queue>/messages/<messageid>?...  # message-id-level
http://127.0.0.1:4593/<account>/?comp=...                         # service-level

Implemented Operations

Every wire operation the @azure/storage-queue client invokes is implemented.

Service-level (QueueServiceClient)

SDK methodHTTPPathNotes
getProperties()GET/?comp=propertiesReturns logging/metrics/CORS XML
setProperties()PUT/?comp=propertiesAccepts and stores; returns 202
getStatistics()GET/?comp=statsReturns geo-replication live
getUserDelegationKey()POST/?comp=userdelegationkeyReturns a deterministic fake signed key
listQueues() / listQueuesSegment()GET/?comp=listSupports prefix, marker, maxresults, include=metadata, pagination via byPage()
createQueue(name)PUT/{queue}Convenience wrapper over queue create
deleteQueue(name)DELETE/{queue}Convenience wrapper over queue delete
getQueueClient(name)Returns a QueueClient (client-side)

Queue-level (QueueClient)

SDK methodHTTPPathNotes
create()PUT/{queue}201 created; idempotent 204 if same metadata
createIfNotExists()PUT/{queue}Composes create + conflict handling
delete()DELETE/{queue}204 deleted; 404 if missing
deleteIfExists()DELETE/{queue}Swallows 404
exists()GET/{queue}?comp=metadataMaps 404 to false
getProperties()GET/{queue}?comp=metadataReturns metadata + x-ms-approximate-messages-count
setMetadata()PUT/{queue}?comp=metadataReplaces metadata
getAccessPolicy()GET/{queue}?comp=aclReturns stored access policies
setAccessPolicy()PUT/{queue}?comp=aclUp to 5 signed identifiers

Messages-level (QueueClient)

SDK methodHTTPPathNotes
sendMessage(text)POST/{queue}/messagesSupports visibilitytimeout, messagettl (-1 = never expires)
receiveMessages()GET/{queue}/messagesSupports numofmessages (1–32), visibilitytimeout; increments DequeueCount, rotates pop receipt
peekMessages()GET/{queue}/messages?peekonly=trueRead without changing visibility
clearMessages()DELETE/{queue}/messagesRemoves all messages

Message-id-level (QueueClient)

SDK methodHTTPPathNotes
updateMessage(id, popReceipt, text, vt)PUT/{queue}/messages/{id}Validates pop receipt; optional text update; returns new x-ms-popreceipt + x-ms-time-next-visible
deleteMessage(id, popReceipt)DELETE/{queue}/messages/{id}Validates pop receipt

Internal (parlel) endpoints

EndpointMethodPurpose
/_parlel/healthGETLiveness check ({ status: "ok", service: "azurequeue", queues: N })
/_parlel/resetPOSTWipe all in-memory state

Message Semantics

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.

FeatureSupportedNotes
Create / delete / list queuesFull lifecycle
Queue metadatax-ms-meta-* round-trip
Approximate message countx-ms-approximate-messages-count
Send / receive / peek / clear messages
Update / delete by message idPop-receipt validated
Visibility timeout & re-deliveryTime-accurate
Message TTL & expiryIncluding -1 (never)
FIFO ordering
Stored access policies (ACL)Up to 5 identifiers
Service properties / statisticsStatic, in-memory
getUserDelegationKeyReturns a deterministic fake key (offline AAD SAS flows)
List pagination (marker / maxresults)
List include=metadata
SAS signature enforcement⟳ Roadmap
Real authentication / authorization⟳ Roadmap
Geo-replication / RA-GRS failover⟳ Roadmap
Server-side encryption / CMK✓ By design — Plain in-memory storage — transport/at-rest crypto is unnecessary locally
Persistence across restarts✓ By design — In-memory by design — fast, isolated, resets cleanly between tests

Error Codes

Errors are returned as Azure-style XML with an x-ms-error-code response header. Validation errors include additional fields (QueryParameterName, QueryParameterValue, MinimumAllowed, MaximumAllowed, Reason) matching the real Azure Queue Storage error envelope:

<?xml version="1.0" encoding="utf-8"?>
<Error>
  <Code>OutOfRangeQueryParameterValue</Code>
  <Message>One of the query parameters specified in the request URI is outside the permissible range.</Message>
  <QueryParameterName>numofmessages</QueryParameterName>
  <QueryParameterValue>0</QueryParameterValue>
  <MinimumAllowed>1</MinimumAllowed>
  <MaximumAllowed>32</MaximumAllowed>
</Error>
HTTPx-ms-error-codeWhen
400OutOfRangeInputQueue name fails validation
400InvalidUriRequest path has no account
400InvalidQueryParameterValueUnsupported comp operation
400InvalidXmlDocumentMore than 5 access policies
400OutOfRangeQueryParameterValuenumofmessages, visibilitytimeout, or messagettl out of range (includes QueryParameterName, QueryParameterValue, MinimumAllowed, MaximumAllowed fields)
400RequestBodyTooLargeMessage text exceeds 64 KiB
400MissingRequiredQueryParameterpopreceipt not supplied to update/delete (includes QueryParameterName field)
400PopReceiptMismatchPop receipt does not match the message
404QueueNotFoundQueue does not exist
404MessageNotFoundMessage id does not exist
405UnsupportedHttpVerbVerb not allowed for the resource
409QueueAlreadyExistsCreate conflicts with existing queue (different metadata)
500InternalErrorUnexpected server error

Environment Variables

VariableDefault
AZURE_STORAGE_ACCOUNTdevstoreaccount1
AZURE_STORAGE_KEYEby8vdM0…GMGw== (Azurite well-known dev key)
AZURE_STORAGE_CONNECTION_STRING…;QueueEndpoint=http://127.0.0.1:4593/devstoreaccount1;
<!-- 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.

AZURE_STORAGE_ACCOUNT=devstoreaccount1
AZURE_STORAGE_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;QueueEndpoint=http://127.0.0.1:4593/devstoreaccount1;
<!-- parlel:testenv:end -->