What happens when you stop picking a stack and let each protocol pick one for you.
Every engineering team has a stack.
Ours has seven, and we did not decide on any of them.
Nevai is a self-hosted, end-to-end encrypted workspace built on Matrix.
Part of it is a set of bridges — 25 of them — connecting Discord, Telegram, WhatsApp, Signal, iMessage, Messenger, Instagram, Slack, Google Chat, LINE, WeChat, KakaoTalk, Skype, GroupMe, SMS, email, IRC, XMPP, Zulip, Mattermost, Revolt, Mumble, QQ, X and LinkedIn into one place.
We started out intending to standardise.
We ended up with this: Language Bridges Go 12 TypeScript 5 Python 4 JavaScript 1 Kotlin 1 PLpgSQL 1 Slice 1 Nobody sat in a room and chose that distribution.
It is what you get when the protocol decides.
Go wins where the protocol was reverse-engineered WhatsApp, Signal, iMessage, Messenger, Instagram, Telegram, X, WeChat, QQ, Skype, LinkedIn, email.
Twelve bridges, and the reason is the same every time: the mature libraries for those protocols are written in Go.
That is not a claim about Go being a better language.
It is a claim about where a decade of reverse-engineering effort happens to live.
If you want to speak WhatsApp's protocol without running a browser session, you use what exists, and what exists is Go.
Look at what leaks in around the edges and the picture gets sharper: Signal is 86% Go and 13% C — the C is libsignal, and you do not reimplement libsignal. iMessage is 96% Go and 3% Objective-C — because iMessage runs on macOS, and at some point you have to talk to the operating system in its own language.
Those percentages are the honest part.
A bridge is mostly your code and a small amount of somebody else's, and the small amount is usually the part that matters most.
Python wins where the API is boring Google Chat, Zulip, KakaoTalk, LINE.
Documented HTTP APIs, JSON in and JSON out, no protocol archaeology required.
There is no performance argument here.
These bridges are not throughput-bound; they are waiting on somebody else's rate limit.
What matters is how quickly you can change them when an API shifts, and for that Python wins comfortably.
Two of these are mixed — LINE is 55% Python and 44% JavaScript, KakaoTalk is 87% Python and 12% JavaScript.
That is client-side work you cannot avoid when part of the protocol only exists in a web app.
TypeScript wins where the event model already fits IRC, XMPP, Revolt, GroupMe, Slack.
Five bridges around protocols that are already event streams.
Matrix is an event stream.
The impedance mismatch is close to zero, so the code is mostly translation rather than architecture.
Revolt is the cleanest of them: 100% TypeScript, no escape hatches.
When the two sides of a bridge agree about what an event is, you get to write only the interesting part.
And then the ones with no choice at all Three bridges are outliers, and each one is an outlier for a concrete reason.
SMS is 73% Kotlin.
SMS is not a network protocol you connect to, it is a thing a phone does.
The only honest place to sit is on Android.
The remaining 27% is Go, because the Matrix side is still the Matrix side.
Mattermost is 86% PLpgSQL.
Stored procedures — because the most reliable way to observe a self-hosted Mattermost is to talk to its Postgres database rather than poll an API that was not designed for this.
Mumble is 64% Slice.
Slice is ZeroC Ice's interface definition language.
It is not a language anyone picks.
It is the language Mumble's control protocol is defined in, so if you want to bridge Mumble, you write Slice.
The rule we ended up with We tried standardising early.
It made three bridges worse and none better — we were writing adapters around adapters to keep a language choice we had made for our own comfort.
The rule now is simple: the platform you are bridging picks the language, and you accept it.
The cost is real.
Seven languages means seven toolchains, seven dependency stories, and a contributor who is fluent in one bridge is a beginner in the n