D-Bus Broker Default
D-Bus Broker Default
NixOS 26.05 made dbus-broker the default system message bus. Classic dbus-daemon still works, but it is no longer the boring path. The boring default is: leave services.dbus.implementation = "broker" (the 26.05 default), treat a bus implementation change as a reboot event (nixos-rebuild boot then reboot), and only pin "dbus" when you have a measured regression — never to silence a switch-inhibitor warning.
Stage 2 systemd services (and most of the desktop session) talk over D-Bus. Swapping the bus under a live session closes sockets that may not reconnect. That is why NixOS labels the option as a switch inhibitor.
Mental model
apps / services / session
│
▼ D-Bus API (same wire protocol)
┌───────────────────────────────┐
│ message bus implementation │
│ "broker" → dbus-broker │ ← NixOS 26.05 default
│ "dbus" → dbus-daemon │ ← opt-out / legacy
└───────────────┬───────────────┘
▼
systemd unit alias: dbus.service
| Concern | Classic dbus |
broker (26.05 default) |
|---|---|---|
| Package | pkgs.dbus |
pkgs.dbus-broker |
| Option value | "dbus" |
"broker" |
| Goal | Reference daemon | Higher performance and reliability, same D-Bus protocol |
| Live switch | Unsafe mid-session | Unsafe mid-session — switch inhibitor |
| Safe apply | nixos-rebuild boot + reboot |
nixos-rebuild boot + reboot |
On a greenfield 26.05 desk host you rarely set the option at all. Explicit = "broker" in snippets below is documentation. Explicit = "dbus" is a deliberate opt-out you should be able to justify in one sentence.
The scary message after an upgrade:
Checking switch inhibitors...
There are changes to critical components of the system:
dbus-implementation : dbus -> broker
Switching into this system is not recommended.
You probably want to run 'nixos-rebuild boot' and reboot your system instead.
That is the system working. Prefer boot + reboot. NIXOS_NO_CHECK=1 forces a live switch that can leave NetworkManager, portals, or the session half-connected to a dead bus.
Worked examples
Case 1: Confirm the bus on a 26.05 desk host
Save as dbus_probe.nix and import it from the host flake (optional — defaults already match):
# dbus_probe.nix
{
# Explicit for clarity on a 26.05 desk host. Omit on greenfield configs.
services.dbus.implementation = "broker";
}After boot:
nixos-option services.dbus.implementation
systemctl status dbus.service --no-pager | head -n 20
busctl status | head -n 15Representative output on a healthy 26.05 desk host:
Value:
"broker"
Default:
"broker"
● dbus.service
Loaded: loaded (…; enabled; alias of dbus-broker.service)
Active: active (running)
dbus.service is an alias. Under broker, the real unit is dbus-broker.service (and the matching user bus). Apps that Requires=dbus.service keep working without knowing which implementation sits behind the name.
Case 2: Upgrade from 25.11 — obey the inhibitor
When the channel/flake input moves to 26.05, the default flips from classic dbus to broker. Evaluation succeeds; activation may refuse a live switch.
# Preferred on the desk after a 26.05 bump:
sudo nixos-rebuild boot --flake .#desk-workstation
sudo systemctl rebootRepresentative inhibitor text if you tried switch instead:
Checking switch inhibitors...
There are changes to critical components of the system:
dbus-implementation : dbus -> broker
Switching into this system is not recommended.
You probably want to run 'nixos-rebuild boot' and reboot your system instead.
Why reboot wins:
- Old bus stops and closes sockets.
- New bus starts.
- Clients that held connections across the restart may never reattach.
- A reboot starts every consumer against the new bus from scratch.
Save a one-line note in the desk runbook (not in Nix):
# DESK-UPGRADE.txt
After bumping nixpkgs to 26.05+: if switch mentions dbus-implementation,
run: nixos-rebuild boot && reboot
Do not export NIXOS_NO_CHECK=1 on a laptop you care about.
Case 3: Opt out only with a measured reason
Some rare clients misbehave with broker. Pin classic dbus after you can reproduce the failure, not because a forum post looked scary.
Save as dbus_legacy_optout.nix:
# dbus_legacy_optout.nix
{
# Temporary incident control — ticket: DESK-1842 (portal disconnect on broker).
# Revisit after the app ships a fix; do not copy this into every host.
services.dbus.implementation = "dbus";
}Apply safely:
sudo nixos-rebuild boot --flake .#desk-workstation
sudo systemctl reboot
nixos-option services.dbus.implementationValue:
"dbus"
Default:
"broker"
The drift between Value and Default is your reminder to remove the pin later.
Case 4: Services that depend on the bus still say dbus.service
Desk units should keep depending on the alias, not on dbus-broker.service by name. That keeps the flake portable if you temporarily opt out.
Save as desk_bus_consumer.nix:
# desk_bus_consumer.nix
{ pkgs, ... }:
{
services.dbus.implementation = "broker";
systemd.services.desk-bus-ping = {
description = "Desk: oneshot that needs a system bus";
wantedBy = [ "multi-user.target" ];
after = [ "dbus.service" ];
wants = [ "dbus.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
# Store paths only.
ExecStart = "${pkgs.systemd}/bin/busctl --system list";
};
};
}sudo nixos-rebuild boot --flake .#desk-workstation && sudo systemctl reboot
# after reboot:
systemctl status desk-bus-ping --no-pager
busctl --system list | headOutput (shape):
● desk-bus-ping.service - Desk: oneshot that needs a system bus
Active: active (exited)
…
org.freedesktop.DBus
org.freedesktop.systemd1
…
Hard-coding after = [ "dbus-broker.service" ]; breaks the day you set implementation = "dbus" on a lab host.
Case 5: Dry-run the inhibitor without guessing
Before you touch a remote desk host, inspect the option merge and prefer boot whenever the implementation changes between generations.
nixos-option services.dbus.implementation
sudo nixos-rebuild dry-activate --flake .#desk-workstationIf dry-activate (or a refused switch) reports a dbus implementation change, schedule a reboot window. For unattended desks, put the upgrade in a two-step job: build + boot, then a controlled reboot — never switch across a bus swap over SSH without a console.
Lab-only force (do not normalize this):
# Lab VM with serial console only — never on the family laptop.
NIXOS_NO_CHECK=1 sudo nixos-rebuild switch --flake .#lab-vmThe trap
Trap A — force the live switch with NIXOS_NO_CHECK=1 to “save time.” You can end up with a graphical session, NetworkManager, or portals still holding sockets to the old bus. The machine looks up; half the desktop is not. Reboot anyway — you paid the risk and still need the reboot.
Trap B — pin services.dbus.implementation = "dbus" on every host to avoid the warning. You freeze the desk on the legacy daemon and re-learn the warning on the next policy cleanup. Leave the 26.05 default; handle the one-time upgrade with boot + reboot.
Trap C — depend on dbus-broker.service by concrete name in custom units. The portable dependency is dbus.service. Broker installs that alias; classic dbus provides the same unit name.
# Anti-pattern — cargo-cult opt-out
{
services.dbus.implementation = "dbus"; # "so switch never complains"
}# Boring fix — accept the default; change process, not the bus
{
# services.dbus.implementation omitted → "broker" on 26.05
}
# Apply bus-affecting upgrades with:
# sudo nixos-rebuild boot --flake .#desk-workstation && sudo systemctl rebootThe boring rule
- On NixOS 26.05+, keep dbus-broker (
"broker"). Do not set the option unless you are opting out with a ticket. - Implementation changes are reboot events:
nixos-rebuild boot, then reboot. Do not normalizeNIXOS_NO_CHECK=1. - Depend on
dbus.service, notdbus-broker.service, in custom units. - Confirm with
nixos-option services.dbus.implementationandsystemctl status dbus.service. - Opt out to
"dbus"only for a reproduced client bug; remove the pin when the bug is gone. - Treat the inhibitor message as documentation, not an error to silence.
Try this
- On a disposable 26.05 VM, run
nixos-option services.dbus.implementationand confirm"broker". Set"dbus",nixos-rebuild boot, reboot, confirm Value/Default drift, then remove the pin and reboot back. - From a 25.11 generation (or a VM snapshot), bump the flake input to 26.05 and attempt
nixos-rebuild switch. Read the inhibitor text. Re-run withbootand reboot. Compare how the session feels vs forcingNIXOS_NO_CHECK=1once in the lab. - Add Case 4’s
desk-bus-pingunit. Flip implementation to"dbus"and back without changing the unit’safter = [ "dbus.service" ];. Confirm it still orders correctly. systemctl show dbus.service -p Id -p Names -p FragmentPathunder broker and under classic dbus. Note the alias vs concrete unit names.- Grep the desk flake for
NIXOS_NO_CHECK,implementation = "dbus", and hard-codeddbus-broker.servicedependencies. Open tickets for each hit that lacks a justification comment.