Without pain, without sacrifice, we would have nothing, Fight Club.

With the core Wayland stack (Niri, greetd, and Noctalia) installed, the next step is tailoring the compositor to your specific workflow. Niri uses the KDL (KDL Document Language) syntax for its configuration file, typically located at ~/.config/niri/config.kdl. Unlike the INI-like syntax of i3 or Sway, KDL offers a structured, node-based format that clearly defines relationships between settings.
The configuration below sets up a productive environment by defining named workspaces (a, b, c, d), applying window rules —such as rounded corners and maximizing new windows— and integrating Noctalia Shell for status bars and notifications. It also includes comprehensive keybindings for navigation, media controls, and launching applications, ensuring a seamless transition from installation to daily use.
// ── Niri config.kdl ──────────────────────────────────────────────────────────
// Location (via symlink): ~/.config/niri/config.kdl
// Source: ~/dotfiles/myArch/config/niri/config.kdl
//
// Niri uses KDL (https://kdl.dev) — not TOML, not YAML.
// KDL syntax: node-name key=value { child-nodes }
// Comments use //
//
// Niri concepts vs i3:
// i3: fixed-size tiling, workspaces are full-screen containers
// Niri: windows tile HORIZONTALLY in an infinite scroll per workspace
// Workspaces are VERTICAL — Super+1/2/3 to switch, Super+Shift+1 to move
// Overview (Super+O) = bird's-eye of all workspaces on all monitors
// ─────────────────────────────────────────────────────────────────────────────
prefer-no-csd
// ── Input ─────────────────────────────────────────────────────────────────────
input {
keyboard {
// XKB is the keyboard mapping system used by Wayland and X11.
xkb {
// Defines the keyboard layout (US English)
layout "us"
// Remaps Caps Lock to Escape (vim-friendly)
options "caps:escape"
}
// Wait 300ms before repeating (milliseconds)
repeat-delay 300
// Repeat every 50ms (20 characters per second)
repeat-rate 50
}
// Window gains focus when mouse enters it (sloppy focus).
focus-follows-mouse max-scroll-amount="0%"
}
// ── Output (monitors) ─────────────────────────────────────────────────────────
// Run: niri msg outputs. List all outputs with their capabilities.
output "eDP-1" {
// Format: "widthxheight@refresh_rate"
mode "1920x1080@60"
// Scaling factor for HiDPI displays, e.g., 1.0 = no scaling
scale 1.0
position x=0 y=0
}
output "HDMI-A-1" {
mode "1920x1080@60"
scale 1.0
position x=1920 y=0
}
// Named workspaces provide semantic meaning: a (Alacritty), b (browsing), c (code), d (miscellaneous)
// Empty braces { } indicate no special configuration (using defaults).
workspace "a" {
}
workspace "b" {
}
workspace "c" {
}
workspace "d" {
}
// ── Window rules and appearance ─────────────────────────────────────────────────────────
window-rule {
// Rounded corners by 12 pixels for a modern look
geometry-corner-radius 12
// Clip window contents to rounded corner boundaries
// Without this, corners are rounded but contents overflow as rectangles
clip-to-geometry true
// All windows start maximized (fill workspace width)
open-maximized true
}
window-rule {
match app-id="code"
open-on-workspace "c"
}
// Application-Specific Rules
// Finding App-IDs: niri msg windows,
window-rule {
match app-id="org.gnome.Nautilus"
open-on-workspace "b"
}
window-rule {
match app-id="google-chrome"
open-on-workspace "d"
}
window-rule {
match app-id="Alacritty"
open-on-workspace "a"
}
// ── Layout ────────────────────────────────────────────────────────────────────
layout {
// Adds 8 pixels of spacing around windows
gaps 8
// Always show borders (even for single window)
// Width of the window border in pixels
border {
width 2
}
// Focus ring — shown when border is off, or in addition to border
focus-ring {
off // Disable additional focus ring (border is enough)
}
// Default column width — windows start at this fraction of screen width
// "proportion" means fraction of the usable width (0.0 to 1.0)
default-column-width { proportion 0.5; }
// New windows start at 50% of screen width
// Better UX: keep focused column centered ("never" GNOME-like)
center-focused-column "on-overflow"
always-center-single-column
}
// ── Debug settings required by Noctalia ───────────────────────────────────────
debug {
// Required for Noctalia's notification actions and window activation.
// Without this, clicking "Open" in a notification may not bring the
// window to focus.
honor-xdg-activation-with-invalid-serial
}
// ── Noctalia wallpaper / overview settings ────────────────────────────────────
// Option 1: Blurred overview wallpaper (recommended).
// Noctalia renders a blurred+dimmed copy of your wallpaper behind the overview.
// Requires "Enable overview wallpaper" to be ON in Noctalia settings.
layer-rule {
match namespace="^noctalia-overview*"
place-within-backdrop true
}
// Startup Applications
// ── Startup: launch Noctalia Shell ────────────────────────────────────────────
// Provides: Status bar, launcher, notifications, control center
spawn-at-startup "qs" "-c" "noctalia-shell"
// ── Startup: XWayland satellite ───────────────────────────────────────────────
// xwayland-satellite starts XWayland on-demand for X11 applications.
// Remove this line if you have no X11 apps.
spawn-at-startup "xwayland-satellite"
// ── Startup: polkit agent ─────────────────────────────────────────────────────
// Required for GUI privilege escalation dialogs
spawn-at-startup "systemd-run" "--user" "--scope" "/usr/lib/polkit-kde-authentication-agent-1"
// ── Startup: clipboard history ────────────────────────────────────────────────
// cliphist watches the clipboard and stores history.
// Noctalia's clipboard widget reads from cliphist.
spawn-at-startup "wl-paste" "--watch" "cliphist" "store"
// Network applet. NetworkManager system tray icon
// Shows WiFi status and connections
spawn-at-startup "nm-applet"
// Application Autostart
spawn-at-startup "code" "/mnt/data/justtothepoint/"
spawn-at-startup "nautilus"
spawn-at-startup "google-chrome-stable"
spawn-at-startup "alacritty"
// ── Keybindings ───────────────────────────────────────────────────────────────
// Mod = Super (Windows key)
// Syntax: binds { key { action; } }
binds {
// ── Noctalia IPC keybindings ──────────────────────────────────────────────
// App launcher (like rofi -show drun)
Mod+Space { spawn "qs" "-c" "noctalia-shell" "ipc" "call" "launcher" "toggle"; }
// Rofi launcher (FAST, minimal)
Mod+D {
spawn-sh "rofi -show drun";
}
// Overview: bird's-eye view of all workspaces
Mod+O { toggle-overview; }
// Control centre (wifi, volume, etc.)
Mod+C { spawn "qs" "-c" "noctalia-shell" "ipc" "call" "controlCenter" "toggle"; }
// Notification centre
Mod+N { spawn "noctalia-shell" "ipc" "call" "notificationCenter" "toggle"; }
// Lock screen
Mod+L { spawn "noctalia-shell" "ipc" "call" "lockScreen" "lock"; }
// ── Applications ──────────────────────────────────────────────────────────
Mod+Return { spawn "alacritty"; }
Mod+B { spawn "firefox"; }
Mod+E { spawn "thunar"; }
// ── Screenshots (Niri built-in) ───────────────────────────────────────────
// Screenshots saved to ~/Pictures/Screenshots/ by default
Mod+S { screenshot; } // interactive region picker
Ctrl+Print { screenshot-screen; } // full screen
Alt+Print { screenshot-window; } // focused window only
// ── Window management ─────────────────────────────────────────────────────
Mod+Q { close-window; }
Mod+F { maximize-column; } // Maximize column (fills screen width)
Mod+Shift+F { fullscreen-window; } // Fullscreen window (no borders, covers entire screen)
// Focus movement (vim keys and arrows)
Mod+H { focus-column-left; }
Mod+L { focus-column-right; }
Mod+J { focus-window-down; }
Mod+K { focus-window-up; }
Mod+Left { focus-column-left; }
Mod+Right { focus-column-right; }
Mod+Down { focus-window-down; }
Mod+Up { focus-window-up; }
// Move windows
Mod+Shift+Left { move-column-left; }
Mod+Shift+Right { move-column-right; }
Mod+Shift+Down { move-window-down; }
Mod+Shift+Up { move-window-up; }
// Column width
Mod+Minus { set-column-width "-10%"; }
Mod+Equal { set-column-width "+10%"; }
// Window height
Mod+Shift+Minus { set-window-height "-10%"; }
Mod+Shift+Equal { set-window-height "+10%"; }
// Floating
Mod+V { toggle-window-floating; }
// ── Workspaces ────────────────────────────────────────────────────────────
// Switch to workspace N
Mod+1 { focus-workspace 1; }
Mod+2 { focus-workspace 2; }
Mod+3 { focus-workspace 3; }
Mod+4 { focus-workspace 4; }
Mod+5 { focus-workspace 5; }
Mod+6 { focus-workspace 6; }
Mod+7 { focus-workspace 7; }
Mod+8 { focus-workspace 8; }
Mod+9 { focus-workspace 9; }
Mod+Shift+1 { move-column-to-workspace 1; }
Mod+Shift+2 { move-column-to-workspace 2; }
Mod+Shift+3 { move-column-to-workspace 3; }
Mod+Shift+4 { move-column-to-workspace 4; }
Mod+Shift+5 { move-column-to-workspace 5; }
Mod+Shift+6 { move-column-to-workspace 6; }
Mod+Shift+7 { move-column-to-workspace 7; }
Mod+Shift+8 { move-column-to-workspace 8; }
Mod+Shift+9 { move-column-to-workspace 9; }
// Scroll workspaces
Mod+Page_Down { focus-workspace-down; }
Mod+Page_Up { focus-workspace-up; }
Mod+Shift+Page_Down { move-column-to-workspace-down; }
Mod+Shift+Page_Up { move-column-to-workspace-up; }
// ── Volume / brightness ───────────────────────────────────────────────────
XF86AudioRaiseVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%+"; }
XF86AudioLowerVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%-"; }
XF86AudioMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }
XF86AudioMicMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SOURCE@" "toggle"; }
XF86MonBrightnessUp allow-when-locked=true { spawn "brightnessctl" "s" "5%+"; }
XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "s" "5%-"; }
XF86AudioPlay { spawn "playerctl" "play-pause"; }
XF86AudioNext { spawn "playerctl" "next"; }
XF86AudioPrev { spawn "playerctl" "previous"; }
// ── Niri system ───────────────────────────────────────────────────────────
// Cycle to a random wallpaper (swww with fade transition)
// Mod+W { spawn "sh" "-c" "swww img $(find ~/wallpaper -type f \( -name '*.jpg' -o -name '*.jpeg' -o -name '*.png' -o -name '*.webp' \) | shuf -n1) --transition-type fade --transition-duration 1"; }
Mod+Shift+E { quit; } // Exit Niri (returns to greetd login)
// Power off system
Mod+Shift+D { spawn "systemctl" "poweroff"; }
// Reload Niri config without restart
Mod+Shift+R { spawn "niri" "msg" "reload-config"; }
}
Check Configuration Syntax: niri --validate-config