niri-dynamic-workspaces

Install
Nix (flake)
# flake.nix inputs
niri-dynamic-workspaces.url = "github:nickolaj-jepsen/niri-dynamic-workspaces";
Build directly:
Home Manager module
# Add to your Home Manager imports
imports = [ inputs.niri-dynamic-workspaces.homeModules.default ];
# Enable
programs.niri-dynamic-workspaces = {
enable = true;
keybind = "Mod+D"; # default — open switcher
deleteKeybind = "Mod+Ctrl+D"; # default — open delete overlay
moveWindowKeybind = "Mod+Shift+D"; # default — open move-window overlay
daemon = true; # default — start daemon at login
settings = {
general.workspace_prefix = "dyn-";
};
};
This installs the package, adds a niri keybind, and writes the config file.
Cargo
Requires GTK4, gtk4-layer-shell, and pkg-config development headers.
Configuration
Config file: ~/.config/niri-dynamic-workspaces/config.toml
All fields are optional with sensible defaults.
[]
= "dyn-" # prefix for dynamic workspace names
= ["kitty"] # programs launched when creating any new workspace
= true # daemon: auto-delete empty unfocused workspaces
= "qwerty" # keyboard layout for the overlay (see table below)
# [layout] options below are no longer used (kept for backwards compatibility).
# The overlay now displays a virtual keyboard layout instead of a card grid.
# max_columns = 4
# min_columns = 2
# max_windows_per_card = 4
# app_name_max_chars = 12
# window_title_max_chars = 18
[]
= ["Escape", "Ctrl+c", "Ctrl+w", "Ctrl+q"] # keys to dismiss the overlay
[] # key: a-z or 0-9
= "Browser" # optional display name shown on the key
= ["firefox", "slack"] # programs launched on create (replaces defaults)
# Configured workspaces that don't exist yet appear as muted keys with a dashed border.
[]
= ["kitty --title myterm"] # arguments supported via whitespace splitting
[] # digit workspaces work too
= "Comms"
= ["slack", "discord"]
Available keyboard layouts
| Layout | Value |
|---|---|
| QWERTY | qwerty |
| AZERTY | azerty |
| QWERTZ | qwertz |
| Dvorak | dvorak |
| Colemak | colemak |
All layouts contain the same 36 keys (a–z, 0–9) arranged in the physical positions of each keyboard layout. The value is case-insensitive.
Usage
niri-dynamic-workspacesorniri-dynamic-workspaces switch— opens the switcher overlay (press key to switch/create)niri-dynamic-workspaces delete— opens the delete overlay (press key to delete)niri-dynamic-workspaces move-window— opens the move-window overlay (press key to move the focused window)niri-dynamic-workspaces daemon— starts as a background daemon (no overlay shown)
All modes support toggle behavior: running the same command again closes the overlay.
Direct mode (no overlay)
Pass a workspace key to act immediately without opening the overlay:
Daemon mode
By default the overlay process starts fresh each time a keybind is pressed, which includes GTK and CSS initialization. For faster overlay display, start a background daemon at login:
spawn-at-startup "niri-dynamic-workspaces" "daemon"
The daemon keeps GTK initialized and subsequent switch/delete/move-window invocations are forwarded to it over D-Bus, skipping startup overhead.
The Home Manager module enables daemon mode by default. To disable it:
programs.niri-dynamic-workspaces.daemon = false;
Development
Enter the dev shell and build:
Lint and test: