Skip to content

Add systemd support for niri with hot reloading#156

Open
DavHau wants to merge 2 commits into
Lassulus:mainfrom
DavHau:niri-systemd
Open

Add systemd support for niri with hot reloading#156
DavHau wants to merge 2 commits into
Lassulus:mainfrom
DavHau:niri-systemd

Conversation

@DavHau
Copy link
Copy Markdown
Contributor

@DavHau DavHau commented May 7, 2026

see commit messages

DavHau added 2 commits May 7, 2026 11:14
NixOS s `systemd.packages` only scans `$pkg/etc/systemd/<type>/*` and
`$pkg/lib/systemd/<type>/*` (see nixpkgs nixos/lib/systemd-lib.nix
around the `for fn in $i/etc/systemd/${typeDir}/* $i/lib/systemd/...`
loop). The README s documented `systemd.packages = [ x.outputs.systemd-user ]`
was therefore a silent no-op: units placed at `$pkg/systemd/<type>/`
were invisible to NixOS s scanner, so nothing landed under
`/etc/systemd/<type>/`.

Move the writeTextDir target into `lib/systemd/<type>/` so the units
land where NixOS already looks. Tests updated accordingly.
Replaces the previous `filesToPatch` of upstream s
`share/systemd/user/niri.service` with a unit generated through the
`wlib.modules.systemd` helper (now imported by this module).

The new unit:

  - bootstraps a mutable runtime copy of the config under
    `%t/niri/config.kdl` (= `$XDG_RUNTIME_DIR/niri/config.kdl`) via
    `ExecStartPre`, and points niri at that copy with `--config`.
  - declares `ExecReload` as two commands: re-stamp the runtime copy
    from the latest immutable nix-store snapshot, then issue
    `niri msg action load-config-file` so niri re-reads the file
    without restarting.
  - sets `reloadIfChanged = true`. Combined with the upstream nixpkgs
    `programs.niri` module, this tells NixOS s switch-to-configuration
    to convert every "needs restart" verdict on niri.service into a
    `systemctl --user reload`, letting `nixos-rebuild switch` apply
    config-only tweaks without dropping the live session.

Shell-launched wrappers retain the upstream behaviour: `NIRI_CONFIG`
points directly at the build-pinned `/nix/store/...niri.kdl`, so the
wrapper script does not depend on `$XDG_RUNTIME_DIR` being set (which
would break under `set -u` in non-systemd contexts -- e.g. the niri
flake check).

Depends on the lib/systemd/<type> unit-dir fix; without it the
generated unit lands somewhere NixOS s `systemd.packages` does not
scan and the whole pipeline is a no-op.
@aquifolly
Copy link
Copy Markdown
Contributor

there's also #135

@Lassulus
Copy link
Copy Markdown
Owner

I cherry picked the first commit onto the main branch, for the hot reload I will talk to @zimward if he is fine with that change or he prefers another approach (like in #135)

Comment thread modules/niri/module.nix
Comment on lines +344 to +349
ExecStartPre = "${config.pkgs.coreutils}/bin/install -Dm644 ${config."config.kdl".path} %t/niri/config.kdl";
ExecStart = "${config.exePath} --session --config %t/niri/config.kdl";
ExecReload = [
"${config.pkgs.coreutils}/bin/install -Dm644 ${config."config.kdl".path} %t/niri/config.kdl"
"${config.exePath} msg action load-config-file"
];
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ExecStartPre = "${config.pkgs.coreutils}/bin/install -Dm644 ${config."config.kdl".path} %t/niri/config.kdl";
ExecStart = "${config.exePath} --session --config %t/niri/config.kdl";
ExecReload = [
"${config.pkgs.coreutils}/bin/install -Dm644 ${config."config.kdl".path} %t/niri/config.kdl"
"${config.exePath} msg action load-config-file"
];
ExecStart = "${config.exePath} --session --config ${config."config.kdl".path}";
ExecReload = "${config.exePath} msg action load-config-file --path ${config."config.kdl".path}";

with niri 26.05 there is no reason to do mutable copies at the config file can just be relocated (infact i implemented that feature exactly for this reason in niri :) )

Comment thread modules/niri/module.nix
Comment on lines +324 to +328
# Systemd-launched session: bootstrap a mutable runtime copy under
# $XDG_RUNTIME_DIR (systemd specifier %t) and point niri at it via
# `--config`. ExecReload re-stamps that file with the latest immutable
# snapshot and asks niri to re-read it via IPC, so config-only switches
# apply without dropping the session.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Systemd-launched session: bootstrap a mutable runtime copy under
# $XDG_RUNTIME_DIR (systemd specifier %t) and point niri at it via
# `--config`. ExecReload re-stamps that file with the latest immutable
# snapshot and asks niri to re-read it via IPC, so config-only switches
# apply without dropping the session.

no longer relevant

Comment thread modules/niri/module.nix
Comment on lines +319 to +323

# Shell-launched wrapper: same behaviour as upstream -- niri reads the
# immutable, build-pinned config straight from /nix/store.
config.env.NIRI_CONFIG = toString config."config.kdl".path;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Shell-launched wrapper: same behaviour as upstream -- niri reads the
# immutable, build-pinned config straight from /nix/store.
config.env.NIRI_CONFIG = toString config."config.kdl".path;
config.env.NIRI_CONFIG = toString config."config.kdl".path;

this should be obvious. no point in having a LLM comment for it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants