D-Bus was introduced by GNOME folks about 20 years ago. For software made only 20 years ago, as opposed to 40 like X, it’s surprisingly almost equally as bad.
As a service, D-Bus is incredibly handy and useful, and overall, I believe the idea should absolutely be used by more apps. However, the implementation... oh boy.
What is D-Bus?
Everyone has heard about D-Bus, but what is it, actually?
D-Bus’ idea is pretty simple: let applications, services and other things expose methods or properties in a way that other apps can find them in one place, on the bus.
Let’s say we have a service that monitors the weather. Instead of each app knowing how to talk to each weather service, or even worse, implementing one itself, it can connect to the bus, and see if any service on the…
D-Bus was introduced by GNOME folks about 20 years ago. For software made only 20 years ago, as opposed to 40 like X, it’s surprisingly almost equally as bad.
As a service, D-Bus is incredibly handy and useful, and overall, I believe the idea should absolutely be used by more apps. However, the implementation... oh boy.
What is D-Bus?
Everyone has heard about D-Bus, but what is it, actually?
D-Bus’ idea is pretty simple: let applications, services and other things expose methods or properties in a way that other apps can find them in one place, on the bus.
Let’s say we have a service that monitors the weather. Instead of each app knowing how to talk to each weather service, or even worse, implementing one itself, it can connect to the bus, and see if any service on the system exposes some weather API, then use it to get weather.
Great, right? And yeah, the idea is wonderful.
What went wrong?
D-Bus is a lenient, unorganized and forgiving bus. Those three add to one of the biggest, fundamental, and conceptual blunders to any protocol, language or system.
The most important blunders are:
- Objects on the bus can register whatever they want.
- Objects on the bus can call whatever they want, however they want, whenever they want.
- The protocol allows and even in a sense incentivises vendor-specific unchecked garbage.
What this means in practice is the definition of "Garbage in, garbage out".
D-Bus standards, part 1
Okay, apps need to communicate, right? Well, in some way right? Where do we find the way?
Uhh... somewhere online, probably. Nobody actually knows because some of them are here, some there, many are unfinished, unreadable, or convoluted garbage docs, and no client follows them anyways.
Let’s take a look at some gems. These are actual docs

Truly secure.

I guess service implementors should learn telepathy.

So is it a draft or widely used?
D-Bus standards are a mess. And that’s if we assume that implementors on both sides actually follow them (they often don’t, as we will learn in a moment...)
D-Bus standards, part 2
Okay, let’s say we have a standard and we understand it. Great! Now...
nobody gives a shit, literally. Even if you read a spec, nothing, literally nothing, guides, ensures, or helps you stick to it. NOTHING. You send anonymous calls with whatever bullshit you want to throw in.
Let me tell you a story...
Back when I was writing xdg-desktop-portal-hyprland, I had to use a few dbus protocols (xdg portals run on dbus) to implement some of the communication. If we go to the portal documentation, we can find the protocols.
Great! So I implemented it. It worked more-or-less. Then, I implemented restore tokens, which allow the app to restore its previously saved share configuration. And here, dbus falls apart.
None of the apps, I repeat, fucking none followed the spec. I wrote a spec-compliant mechanism and nothing fucking used it. Why? Simple, they all used a different spec, which came out of fucking nowhere, I legit couldn’t find a single doc with it. What I ended up doing was I looked at KDE which already had an impl and mimic’d that.
What the actual fuck. "Spec" my ass.
Fun fact: THIS IS STILL THE CASE! The spec advertises a "restore_token" string prop on SelectSources and Start, where no app does this and uses "restore_data" in "options".
D-Bus standards, part 3
Let me just say one word: variants. What in the actual, everloving fuck? Half of D-Bus protocols have either this BS, or some "a{sv}" (array of string + variant) passed somewhere.
Putting something like this, even allowing that in a core spec should be subject to a permanent ban from creating software. What this allows, and even incentivises, is for apps to send random shit over the wire and hope the other side understands it. (see the example above in part 2, prime dbus) This has been tried many times, most notably in X with atoms, and it has time and time again proven to only bring disaster.
D-Bus standards, part 4
Ever heard of permissions? Neither have D-Bus developers. D-Bus is as insecure as it gets. Everybody sees everything and calls whatever. If the app doesn’t have a specific security mechanism, cowabunga it is. Furthermore, there is no such thing as a "rejection" in a universal sense. Either the protocol invents its own "rejection" or just... something happens, god knows what, actually.
This is one of the prime reasons flatpak apps can not see your session bus.
D-Bus standards, part 5
Ever seen kwallet or gnome-keyring? Yeah, these things. These are supposed to be "secret storage" for things like signing keys, passwords, etc. They can be protected by a password, which means they are secure... right?
No. No, they aren’t. These secrets may be encrypted on disk, which technically prevents them from being stolen if your laptop is stolen. If you just cringed at that because disk encryption has been a thing for 20 years now or so, you’re not alone.
However, the best thing is this: any app on the bus can read all secrets in the store if the store is unlocked. No, this is not a fucking joke. Once you input that password, any app can just read all of them without you noticing.
This is the real stance of GNOME developers on the issue:

Honestly, I am at a loss of words as to how to describe this without being extremely rude.
Security so good microsoft might steal it for their recall.
Enough is enough
I’ve had enough of D-Bus in my apps. I would greatly benefit from a session (and later, system) bus for my ecosystem, but I will not stand the absolute shitfest that D-Bus is.
That is why, I’ve decided to take matters into my own hands. I am writing a new bus. From the ground up, with zero copying, interop, or other recognition of D-Bus. There are so many stupid ideas crammed into D-Bus that I do not wish to have any of them poison my own.
XKCD 927

A lot of people quote this xkcd comic for each new implementation. However, this is not exactly the same.
For example, with wayland, when you switch, you abandon X. You cannot run an X11 session together with a wayland one, simply not how it works.
You can, however, run two session buses. Or three. Or 17. Nothing stops you. That’s why gradual migration is absolutely possible. Sure, these buses can’t talk to each other, but you can also create a proxy client that can "translate" dbus APIs into new ones.
Wire
The first thing I focused on was hyprwire. I needed a wire protocol anyways for hypr* stuff like hyprlauncher, hyprpaper, etc.
The wire protocol is inspired by how Wayland decided to handle things. Its most important strengths are:
- consistency: the wire itself enforces types and message arguments. No "a{sv}", no "just send something lol"
- simplicity: the wire protocol is fast and simple. Nobody needs complicated struct types, these just add annoyances.
- speed: fast handshakes and protocol exchanges, connections are estabilished very quickly.
Hyprwire is already used for IPC in hyprpaper, hyprlauncher and parts of hyprctl, and has been serving us well.
Bus
The bus is called hyprtavern, as it is not exactly what D-Bus is, but it’s more like a tavern.
Apps register objects on the bus, which have exposed protocols and key properties defined by the protocols. These objects can be discovered by other apps connecting to the bus.
In a sense, hyprtavern acts like a tavern, where each app is a client, that can advertise the languages they speak, but also go up to someone else and strike up a conversation if they have a language in common.
Some overall improvements over D-Bus, in no particular order:
- Permissions: baked in, in-spec permissions. Suitable for exposing to sandboxed apps by default.
- Strict protocols: don’t know the language? Don’t poison the wire. Worth noting this does not stop you from making your own extensions, it just enforces you stay in-spec.
- Simplified API: D-Bus has a lot of stupid ideas (shoutout broadcast) that we intentionally do not inherit.
- Way better defaults: The core spec also includes a few things that are optional (and dumb) in D-Bus like an actually secure kv store.
Kv
With relation to the Secrets API discussed a bit above, I wanted to mention kv.
hyprtavern-kv is the default implementation of the core protocol for a kv store. A kv store is a "key-value" store, which means apps register values for "keys", e.g. "user_secret_key = password".
This is essentially what D-Bus Secrets API does, but instead of being a security joke, it’s actually secure by-design.
Any app can register secrets, which only it can read back. Secrets cannot be enumerated. This means that when "/usr/bin/firefox" sets a "passwords:superwebsite.com = animebooba", an app called "~/Downloads/totally_legit.sh" can not see the value, or the key, or that firefox even set anything.
This also (will) work with Flatpak, Snap and AppImage applications by additionally using their Flatpak ID, Snap ID or AppImage path respectively. This is not implemented, but planned.
This kv store is always encrypted, but a default password can be used which means it will be unlocked by default and the store file can be trivially decrypted. The difference is that if you set a password here, it will actually be secure, even if an app with access to the bus tries to steal all of the secrets.
Additionally, this protocol is core. It must be implemented by the bus, which means all apps can benefit from a secure secret storage.
Is hyprtavern ready?
No, absolutely not. I started work on it just recently, and I still need to cook a bit. It’s coming though, really!
I hope to get it widely used within hypr* by 0.54 of hyprland (that is the release after the upcoming 0.53).
Do I expect adoption?
No, definitely not at the beginning. But, it’s an easier transition than X11 -> Wayland, and I didn’t expect Hyprland to be widely adopted either, but here we are.
Time will tell. All I can say is that it is just better than D-Bus.
An important part of adoption will probably be bindings to other languages. The libraries are all in C++, but since they aren’t very big (by design), making Rust / Go / Python bindings shouldn’t be hard for someone experienced with those languages.
The wire format is also simple and open, so you could also write a Memory-Safe™ libhyprwire in Rust for example.
Closer
D-Bus has been an annoyance of mine for years now, but I finally have the ecosystem and resources to write something to replace it.
Let’s hope we can make the userspace a bit nicer to work with :)