babelqueue/symfony
A Symfony Messenger serializer that swaps the wire format for the canonical BabelQueue envelope, letting Symfony services exchange messages with Laravel, Go, Python, .NET and Node over one strict JSON format on your existing broker.
composer require babelqueue/symfony// config/bundles.php
BabelQueue\Symfony\BabelQueueBundle::class => ['all' => true],
messenger.transport.native_php_serializer. Keep your Symfony-to-Symfony transports on the native serializer — you only want the canonical envelope on polyglot boundaries.#[AsMessageHandler] can receive.Where to look first: config/packages/messenger.yaml (serializer wiring), the bundle's URN-map config block, and the babelqueue/php-sdk envelope class — that's where the actual JSON shape lives. The Symfony adapter is thin; almost all behavior is in the SDK.
Serializer at the transport level, not globally. Set the BabelQueue serializer on the specific transport(s) that cross language lines. This keeps internal Symfony messages using PHP-native serialization (faster, handles more types) while only paying the JSON/envelope tax at the boundary.
Outbound: plain Messenger messages. Define small DTOs, dispatch through the normal MessageBusInterface, and let the serializer build the envelope. Keep message classes dumb — scalars, arrays, and nested DTOs that map cleanly to JSON. Anything that doesn't survive json_encode/json_decode will bite you.
Inbound: URN map is your routing table. Add one entry per external message type. Handlers stay idiomatic Symfony:
#[AsMessageHandler]
final class HandleOrderShipped { public function __invoke(OrderShipped $m): void { /* ... */ } }
No special base class, no adapter in the handler — that's the main ergonomic win.
Contract-first testing. Since the wire format is the product, unit-test the serializer round-trip without a broker: serialize a message, assert the JSON against a golden fixture, deserialize it back. Commit those fixtures to a shared repo/package so the Go, Python, and Node teams assert against the same bytes. This is the single highest-value habit with a polyglot envelope.
Failure transport parity. If you use failure_transport, configure it with the same BabelQueue serializer, otherwise failed envelopes become unreadable by messenger:failed:show and messenger:failed:retry.
Versioned payloads. Treat the envelope version field as an API contract. Add fields additively, never rename/remove without a coordinated rollout — you cannot atomically redeploy five languages.
babelqueue/php-sdk.DateTime becomes a string, integers beyond 2^53 lose precision in JS consumers, null vs. absent keys are not the same thing, and PHP associative arrays vs. lists can serialize unexpectedly. Normalize on the producer side rather than patching consumers.messenger:consume -vv surfaces decode errors, but the fastest path is inspecting the raw payload with rabbitmqadmin/redis-cli — it's human-readable JSON, so you can see exactly what the producer sent versus what your URN map expects.config/packages/messenger.yaml; get the serializer service id right and confirm with bin/console debug:container | grep -i babel.^8.2, Symfony ^6.4 | ^7.0. Check compatibility before a Symfony major upgrade — a thin adapter can still hard-block your framework upgrade.How can I help you explore Laravel packages today?