D-Bus Broker Default

Updated

September 12, 2026

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 15

Representative 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 reboot

Representative 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:

  1. Old bus stops and closes sockets.
  2. New bus starts.
  3. Clients that held connections across the restart may never reattach.
  4. 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.implementation
Value:
"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 | head

Output (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-workstation

If 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-vm

The 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 reboot

The 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 normalize NIXOS_NO_CHECK=1.
  • Depend on dbus.service, not dbus-broker.service, in custom units.
  • Confirm with nixos-option services.dbus.implementation and systemctl 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

  1. On a disposable 26.05 VM, run nixos-option services.dbus.implementation and confirm "broker". Set "dbus", nixos-rebuild boot, reboot, confirm Value/Default drift, then remove the pin and reboot back.
  2. 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 with boot and reboot. Compare how the session feels vs forcing NIXOS_NO_CHECK=1 once in the lab.
  3. Add Case 4’s desk-bus-ping unit. Flip implementation to "dbus" and back without changing the unit’s after = [ "dbus.service" ];. Confirm it still orders correctly.
  4. systemctl show dbus.service -p Id -p Names -p FragmentPath under broker and under classic dbus. Note the alias vs concrete unit names.
  5. Grep the desk flake for NIXOS_NO_CHECK, implementation = "dbus", and hard-coded dbus-broker.service dependencies. Open tickets for each hit that lacks a justification comment.