--- title: "Glossary of polyglot queue terms" description: "Definitions of the vocabulary BabelQueue’s wire contract uses — polyglot queue, wire envelope, schema_version, URN identity, trace_id, dead-letter queue, idempotency key, transactional outbox, redrive, broker binding and more." source: https://babelqueue.com/glossary/ --- # Glossary of polyglot queue terms 14 terms from the BabelQueue wire contract, each defined on its own. Every definition links to the specification page that states it in full — if this page and the contract ever disagree, the contract wins. ## Polyglot queue Anchor: https://babelqueue.com/glossary/#polyglot-queue A polyglot queue is a message queue whose messages are produced in one programming language and consumed natively in another. It is not a kind of broker — the same Redis, RabbitMQ or SQS queue becomes polyglot when the bytes on it are encoded in a language-neutral format instead of a language-native one. BabelQueue makes a queue polyglot by replacing only the serializer: six SDKs (PHP, Python, Go, Node.js, Java and .NET) read and write one frozen JSON envelope over the broker you already run. See: [Wire contract](https://babelqueue.com/docs/spec/1.x/introduction/) · [What is a polyglot queue?](https://babelqueue.com/blog/what-is-a-polyglot-queue/) ## PHP serialize() lock-in Anchor: https://babelqueue.com/glossary/#php-serialize-lock-in PHP serialize() lock-in is what happens when a queue’s messages are encoded as a PHP object graph: only PHP can read them, and only PHP that still has a class of exactly that name. Laravel’s native queue serializes jobs this way, so the identity on the wire is a fully-qualified class name like App\Jobs\ProcessOrder — meaningless to a Go or Python worker, and broken by an ordinary rename. Every language has its own version of the trap: Python pickle, Java object serialization. The fix is to change the serialization, not the broker or the worker. See: [The envelope](https://babelqueue.com/docs/spec/1.x/envelope/) · [What is a polyglot queue?](https://babelqueue.com/blog/what-is-a-polyglot-queue/) ## Wire envelope Anchor: https://babelqueue.com/glossary/#wire-envelope The wire envelope is the JSON document BabelQueue puts on the queue: job, trace_id, data, meta and attempts, encoded as UTF-8 JSON. It is the entire contract — every SDK in every language produces and consumes exactly this shape, so a message written by one is read natively by another. meta carries id, queue, lang, schema_version and created_at and is immutable after production; top-level attempts is the one field a broker or worker may change. See: [The envelope](https://babelqueue.com/docs/spec/1.x/envelope/) ## schema_version Anchor: https://babelqueue.com/glossary/#schema-version meta.schema_version is the integer that tells a consumer whether it can read an envelope at all. It is currently 1 and frozen there: an additive, optional field keeps the version at 1, while removing, renaming or retyping a field — or changing what one means — requires a bump, an architecture decision record and a compatibility window. A consumer must reject or quarantine a schema_version it does not understand rather than best-effort parse it. See: [Change control](https://babelqueue.com/docs/spec/1.x/envelope/#change-control) · [Why the envelope is frozen](https://babelqueue.com/blog/why-the-envelope-is-frozen/) ## URN identity Anchor: https://babelqueue.com/glossary/#urn-identity A BabelQueue message identifies itself with a URN string in the envelope’s job field, shaped urn:babel:: — for example urn:babel:orders:created. That URN is the only thing a consumer reads to decide which handler runs, so routing never depends on a type shared between services. Because it is a plain, application-owned string, the producing class can be renamed freely and a consumer in any language maps the same URN to its own handler; urn is accepted as an inbound alias when job is absent. See: [URN naming](https://babelqueue.com/docs/spec/1.x/urn/) ## data payload Anchor: https://babelqueue.com/glossary/#data-payload data is the business payload inside the envelope, and it must be a pure JSON object — no PHP objects, closures or resources, no language-native types, no raw bytes. Because six runtimes decode the same bytes, the encoding rules are part of the contract: UTF-8 JSON with no NaN or Infinity; integers within signed 64-bit, and under 2^53−1 if a JavaScript consumer is in the chain; currency in integer minor units or strings rather than floats; binary base64-encoded; times as Unix milliseconds or RFC 3339 UTC strings. What shape data takes behind a given URN is the application’s contract, not the envelope’s. See: [Cross-language data rules](https://babelqueue.com/docs/spec/1.x/envelope/#cross-language-data-rules) · [Payload schema validation](https://babelqueue.com/docs/spec/1.x/schema-validation/) ## trace_id Anchor: https://babelqueue.com/glossary/#trace-id trace_id is the required UUID that ties every message in one causal chain together. The first producer in the chain mints it, and every SDK then preserves and forwards it unchanged across every hop — including onto the dead-letter queue. It is not meta.id, which identifies one single message: when a consumer publishes a downstream message while handling one, it copies the inbound trace_id and mints a new meta.id. See: [Dead-letter & tracing](https://babelqueue.com/docs/spec/1.x/dead-letter-and-tracing/) · [Observability](https://babelqueue.com/docs/spec/1.x/observability/) ## Broker binding Anchor: https://babelqueue.com/glossary/#broker-binding A broker binding defines how one broker carries the canonical envelope natively. The message body is always the envelope, byte-identical across SDKs; the binding additionally projects parts of it onto the broker’s own metadata — an AMQP type and correlation_id, SQS MessageAttributes, an Azure Service Bus Subject — so a consumer can route by URN and continue a trace without decoding the body. That projection is redundant, never a replacement for the body, which is why adding a broker is purely additive and never changes the wire format. See: [Broker bindings](https://babelqueue.com/docs/spec/1.x/broker-bindings/) ## Framework adapter vs transport Anchor: https://babelqueue.com/glossary/#framework-adapter-vs-transport A framework adapter binds BabelQueue to a framework’s own queue system so you keep that framework’s worker and retry machinery — a drop-in Laravel queue driver, a Symfony Messenger serializer, a Spring AMQP message converter. A transport is the much thinner seam that publishes encoded envelopes over one broker client (and, where a runtime ships one, consumes them). Both sit on a single language core that owns the codec, so the envelope cannot drift between them: in PHP, for instance, the whole Transport contract is one publish(string $payload, ?string $queue) method. See: [PHP transports](https://babelqueue.com/docs/php-sdk/1.x/transports/) · [Laravel adapter](https://babelqueue.com/docs/laravel/1.x/introduction/) ## Dead-letter queue (DLQ) Anchor: https://babelqueue.com/glossary/#dead-letter-queue A dead-letter queue is where a message goes when it cannot be processed — retries exhausted, a URN no handler maps, or an undecodable body. BabelQueue’s convention is the source queue name plus a .dlq suffix, so a message that failed on orders lands on orders.dlq as an ordinary canonical envelope that any SDK can read and triage. The dead-lettered message carries one extra optional top-level dead_letter block recording the reason, error, failure time, original queue and attempt count, while the original envelope inside it — trace_id included — is preserved unchanged. Dead-lettering is opt-in per SDK. See: [Dead-letter & tracing](https://babelqueue.com/docs/spec/1.x/dead-letter-and-tracing/) ## Redrive Anchor: https://babelqueue.com/glossary/#redrive Redrive is the operator action of moving dead-lettered messages back onto a live queue for reprocessing. BabelQueue’s redrive removes the dead_letter block and resets attempts to 0 while preserving job, trace_id, data and meta verbatim, so a redriven message is indistinguishable from a fresh one and stays on its original trace. It ships the safe-replay primitives an operator needs: a dry run, a select predicate, a cap on how many messages are pulled, and a target-queue override that routes the replay to a sandbox instead of production. See: [DLQ redrive & replay-bypass](https://babelqueue.com/docs/spec/1.x/redrive-and-replay/) ## Idempotency key Anchor: https://babelqueue.com/glossary/#idempotency-key An idempotency key is the value a consumer dedupes on so a redelivered message is not processed twice. In BabelQueue that key is meta.id, verbatim — the unique identity of one specific message, already required by the frozen envelope, so no new field is needed. Each SDK ships an optional seen-set helper that skips a handler whose meta.id was already processed successfully; a message with no usable meta.id runs unchanged rather than being dropped. Unlike an HTTP idempotency key it stores no response to replay, because a queue handler has none. See: [Idempotency](https://babelqueue.com/docs/spec/1.x/idempotency/) · [Idempotency stores](https://babelqueue.com/docs/spec/1.x/idempotency-stores/) ## Transactional outbox Anchor: https://babelqueue.com/glossary/#transactional-outbox The transactional outbox is a producer-side pattern that removes the dual write — the crash window between committing your business row and publishing the message. The encoded envelope is written to an outbox table inside the same database transaction as the business row, so both commit or neither does, and a separate relay reads those rows afterwards and publishes the stored bytes verbatim. The honest guarantee is an exactly-once handoff into the broker and the usual at-least-once on the wire, with the consumer deduping on meta.id. BabelQueue’s helper defines the store contract and binds to no database driver. See: [Transactional outbox](https://babelqueue.com/docs/spec/1.x/outbox/) ## Conformance suite Anchor: https://babelqueue.com/glossary/#conformance-suite The conformance suite is the executable form of the wire contract: a language-neutral set of fixture envelopes, the canonical JSON Schema, and a manifest stating what a consumer must derive from each fixture. Every SDK vendors a copy and runs it in CI, so if two SDKs both pass, a message one produces is consumable by the other. It covers deliberately invalid envelopes too — an unknown schema_version, or an envelope with no identity field at all, must be rejected rather than best-effort parsed — plus broker-binding cases such as the SQS attribute projection. See: [Cross-SDK parity](https://babelqueue.com/docs/spec/1.x/introduction/) · [Conformance suite on GitHub](https://github.com/BabelQueue/conformance)