NixOS
For NixOS users, a Nix package for Noctalia is available. You can also get the Git version, NixOS module and Home Manager module via flakes.
Nix flakes
Section titled “Nix flakes”To install Noctalia, you need to add a flake input and install the package.
Adding the flake input
Section titled “Adding the flake input”Add the required inputs to your flake configuration:
{ description = "NixOS configuration with Noctalia";
inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
noctalia = { url = "github:noctalia-dev/noctalia-shell"; inputs.nixpkgs.follows = "nixpkgs"; }; };
outputs = inputs@{ self, nixpkgs, ... }: { nixosConfigurations.awesomebox = nixpkgs.lib.nixosSystem { specialArgs = { inherit inputs; }; modules = [ # ... other modules ./noctalia.nix ]; }; };}With the flake installed, we can access Noctalia packages and modules in our configuration.
Installing the package
Section titled “Installing the package”If you don’t use Noctalia’s NixOS or home-manager modules, you need to manually install the default Noctalia package from the new noctalia input:
{ pkgs, inputs, ... }:{ # install package environment.systemPackages = with pkgs; [ inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default # ... maybe other stuff ];}Rebuild with sudo nixos-rebuild switch --flake ..
Config with home-manager
Section titled “Config with home-manager”If you have home manager installed, you can configure your Noctalia shell in Nix.
Noctalia settings
Section titled “Noctalia settings”To configure Noctalia settings, you can use the Noctalia home manager module:
{ pkgs, inputs, ... }:{ home-manager.users.drfoobar = { # import the home manager module imports = [ inputs.noctalia.homeModules.default ];
# configure options programs.noctalia-shell = { enable = true; settings = { # configure noctalia here bar = { density = "compact"; position = "right"; showCapsule = false; widgets = { left = [ { id = "ControlCenter"; useDistroLogo = true; } { id = "WiFi"; } { id = "Bluetooth"; } ]; center = [ { hideUnoccupied = false; id = "Workspace"; labelMode = "none"; } ]; right = [ { alwaysShowPercentage = false; id = "Battery"; warningThreshold = 30; } { formatHorizontal = "HH:mm"; formatVertical = "HH mm"; id = "Clock"; useMonospacedFont = true; usePrimaryColor = true; } ]; }; }; colorSchemes.predefinedScheme = "Monochrome"; general = { avatarImage = "/home/drfoobar/.face"; radiusRatio = 0.2; }; location = { monthBeforeDay = true; name = "Marseille, France"; }; }; # this may also be a string or a path to a JSON file, # but in this case must include *all* settings. }; };}We don’t have extensive documentation of Noctalia’s configuration options; however, you can see an up-to-date list of configuration defaults.
Additionally, if you use the systemd service, editing the settings with the GUI will show the resulting configuration in ~/.config/noctalia/gui-settings.json. You can then use this information to update your Nix config to make it permanent.
Theme colors
Section titled “Theme colors”To configure Noctalia settings, you can use the Noctalia home manager module. Be sure to set every Material 3 color, including hover-state values, when overriding the defaults:
{ pkgs, inputs, ... }:{ home-manager.users.drfoobar = { # import the home manager module imports = [ inputs.noctalia.homeModules.default ];
# configure options programs.noctalia-shell = { enable = true; colors = { # you must set ALL of these mError = "#dddddd"; mOnError = "#111111"; mOnPrimary = "#111111"; mOnSecondary = "#111111"; mOnSurface = "#828282"; mOnSurfaceVariant = "#5d5d5d"; mOnTertiary = "#111111"; mOnHover = "#ffffff"; mOutline = "#3c3c3c"; mPrimary = "#aaaaaa"; mSecondary = "#a7a7a7"; mShadow = "#000000"; mSurface = "#111111"; mHover = "#1f1f1f"; mSurfaceVariant = "#191919"; mTertiary = "#cccccc"; }; # this may also be a string or a path to a JSON file. }; };}User Templates
Section titled “User Templates”The user-templates option allows you to define custom Matugen templates.
This is useful for theming other applications that are not supported by default.
It can be a string, a path, or an attribute set.
As a string:
{ pkgs, inputs, ... }:{ home-manager.users.drfoobar = { # ... programs.noctalia-shell = { enable = true; settings = { templates = { enableUserTemplates = true; }; }; user-templates = '' [config] # General Matugen config settings [templates.myapp] input_path = "~/.config/noctalia/templates/myapp.css" output_path = "~/.config/myapp/theme.css" post_hook = "myapp --reload-theme" ''; }; };}As a path:
{ pkgs, inputs, ... }:{ home-manager.users.drfoobar = { # ... programs.noctalia-shell = { enable = true; settings = { templates = { enableUserTemplates = true; }; }; user-templates = ./path/to/user-templates.toml; }; };}As an attribute set:
{ pkgs, inputs, ... }:{ home-manager.users.drfoobar = { # ... programs.noctalia-shell = { enable = true; settings = { templates = { enableUserTemplates = true; }; }; user-templates = { config = { # General Matugen config settings }; templates = { myapp = { input_path = "~/.config/noctalia/templates/myapp.css"; output_path = "~/.config/myapp/theme.css"; post_hook = "myapp --reload-theme"; }; }; }; }; };}Wallpapers
Section titled “Wallpapers”Wallpapers are configured in ~/.cache/noctalia/wallpapers.json. You can set them declaratively:
{ pkgs, inputs, ... }:{ home-manager.users.drfoobar = { # ... other config ...
home.file.".cache/noctalia/wallpapers.json" = { text = builtins.toJSON { defaultWallpaper = "/path/to/default/wallpaper.png"; wallpapers = { "DP-1" = "/path/to/monitor/wallpaper.png"; }; }; }; };}Keybinds
Section titled “Keybinds”Keybindings are configured in your compositor. You make IPC calls to Noctalia as explained in the keybinds section. The only difference is that you can call noctalia-shell instead of qs -c noctalia-shell.
To safely configure noctalia keybindings in the Niri flake, be sure to pass a list:
{ pkgs, inputs, ... }:{ # ... home-manager.users.drfoobar = { config, ... }: { # ... programs.niri = { settings = { # ... binds = with config.lib.niri.actions; { "Mod+Space".action.spawn = [ "noctalia-shell" "ipc" "call" "launcher" "toggle" # ✅ ]; "Mod+P".action.spawn = "noctalia-shell ipc call sessionMenu toggle"; # ❌ }; }; };}It may be convenient to define a utility function to allow you to use simple strings:
{ pkgs, inputs, ... }:
let noctalia = cmd: [ "noctalia-shell" "ipc" "call" ] ++ (pkgs.lib.splitString " " cmd);in{ # ... home-manager.users.drfoobar = { config, lib, ... }: { # ... programs = { niri = { # ... settings = { binds = with config.lib.niri.actions; { # ... "Mod+L".action.spawn = noctalia "lockScreen lock"; "XF86AudioLowerVolume".action.spawn = noctalia "volume decrease"; "XF86AudioRaiseVolume".action.spawn = noctalia "volume increase"; "XF86AudioMute".action.spawn = noctalia "volume muteOutput"; # etc }; }; }; };}Running the shell
Section titled “Running the shell”The Noctalia shell can now be run in two ways: manually or using a systemd service
Running manually
Section titled “Running manually”To run Noctalia using the flake, run:
noctalia-shellWith the Niri flake, you can then spawn Noctalia on startup like this:
{ pkgs, inputs, ... }:{ # ...
home-manager.users.drfoobar = { # ... programs.niri = { package = niri; settings = { # ... spawn-at-startup = [ { command = [ "noctalia-shell" ]; } ]; }; }; };}Running with systemd
Section titled “Running with systemd”You can set up systemd service via NixOS module or Home Manager module. If you configure Noctalia shell with home-manager, then Home Manager module is a better choice. It’s best not to enable systemd service in both modules at the same time, as names of two systemd services are the same; it’s unpredictable which one will run (usually, it’s the systemd service in Home Manager module).
NixOS module
Section titled “NixOS module”Import the Noctalia NixOS modules and enable the service:
{ pkgs, inputs, ... }:{ # import the nixos module imports = [ inputs.noctalia.nixosModules.default ]; # enable the systemd service services.noctalia-shell.enable = true;}The service will start after graphical-session.target by default, which will work correctly out of the box for Niri and Hyprland with UWSM.
If you have some custom target, you can configure it with the target option:
{ pkgs, inputs, ... }:{ # ... services.noctalia-shell = { enable = true; target = "my-hyprland-session.target"; };}This target depends on how you configure your Hyprland session systemd service.
Home Manager module
Section titled “Home Manager module”Import the Noctalia Home Manager modules and enable the service:
{ pkgs, inputs, ... }:{ home-manager.users.drfoobar = { # import the home manager module imports = [ inputs.noctalia.homeModules.default ];
# enable the systemd service programs.noctalia-shell.systemd.enable = true; };}The systemd service target is set by the wayland.systemd.target option in Home Manager.
Calendar events support
Section titled “Calendar events support”To add support for events in the calendar via evolution-data-server.
First, enable the evolution-data-server:
services.gnome.evolution-data-server.enable = true;Then override the Noctalia package:
pkgs.noctalia-shell.override { calendarSupport = true; }or
inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default.override { calendarSupport = true; }Configuration Defaults
Section titled “Configuration Defaults”There is no comprehensive documentation of all configuration options, but the default values are autogenerated and placed in a settings-default.json in the Noctalia shell repository. We retrieve a live Nixified version of these here for your convenience:
{ pkgs, inputs, ... }:{ home-manager.users.drfoobar = { imports = [ inputs.noctalia.homeModules.default ];
programs.noctalia-shell = { enable = true; settings = { settingsVersion = 0; bar = { position = "top"; monitors = [ ]; density = "default"; showOutline = false; showCapsule = true; capsuleOpacity = 1; backgroundOpacity = 0.93; useSeparateOpacity = false; floating = false; marginVertical = 0.25; marginHorizontal = 0.25; outerCorners = true; exclusive = true; widgets = { left = [ { icon = "rocket"; id = "CustomButton"; leftClickExec = "qs -c noctalia-shell ipc call launcher toggle"; } { id = "Clock"; usePrimaryColor = false; } { id = "SystemMonitor"; } { id = "ActiveWindow"; } { id = "MediaMini"; } ]; center = [ { id = "Workspace"; } ]; right = [ { id = "ScreenRecorder"; } { id = "Tray"; } { id = "NotificationHistory"; } { id = "Battery"; } { id = "Volume"; } { id = "Brightness"; } { id = "ControlCenter"; } ]; }; }; general = { avatarImage = ""; dimmerOpacity = 0.2; showScreenCorners = false; forceBlackScreenCorners = false; scaleRatio = 1; radiusRatio = 1; iRadiusRatio = 1; boxRadiusRatio = 1; screenRadiusRatio = 1; animationSpeed = 1; animationDisabled = false; compactLockScreen = false; lockOnSuspend = true; showSessionButtonsOnLockScreen = true; showHibernateOnLockScreen = false; enableShadows = true; shadowDirection = "bottom_right"; shadowOffsetX = 2; shadowOffsetY = 3; language = ""; allowPanelsOnScreenWithoutBar = true; }; ui = { fontDefault = ""; fontFixed = ""; fontDefaultScale = 1; fontFixedScale = 1; tooltipsEnabled = true; panelBackgroundOpacity = 0.93; panelsAttachedToBar = true; settingsPanelMode = "attached"; wifiDetailsViewMode = "grid"; bluetoothDetailsViewMode = "grid"; bluetoothHideUnnamedDevices = false; }; location = { name = "Tokyo"; weatherEnabled = true; weatherShowEffects = true; useFahrenheit = false; use12hourFormat = false; showWeekNumberInCalendar = false; showCalendarEvents = true; showCalendarWeather = true; analogClockInCalendar = false; firstDayOfWeek = -1; }; calendar = { cards = [ { enabled = true; id = "calendar-header-card"; } { enabled = true; id = "calendar-month-card"; } { enabled = true; id = "timer-card"; } { enabled = true; id = "weather-card"; } ]; }; screenRecorder = { directory = ""; frameRate = 60; audioCodec = "opus"; videoCodec = "h264"; quality = "very_high"; colorRange = "limited"; showCursor = true; copyToClipboard = false; audioSource = "default_output"; videoSource = "portal"; }; wallpaper = { enabled = true; overviewEnabled = false; directory = ""; monitorDirectories = [ ]; enableMultiMonitorDirectories = false; recursiveSearch = false; setWallpaperOnAllMonitors = true; fillMode = "crop"; fillColor = "#000000"; randomEnabled = false; wallpaperChangeMode = "random"; randomIntervalSec = 300; transitionDuration = 1500; transitionType = "random"; transitionEdgeSmoothness = 0.05; panelPosition = "follow_bar"; hideWallpaperFilenames = false; useWallhaven = false; wallhavenQuery = ""; wallhavenSorting = "relevance"; wallhavenOrder = "desc"; wallhavenCategories = "111"; wallhavenPurity = "100"; wallhavenRatios = ""; wallhavenApiKey = ""; wallhavenResolutionMode = "atleast"; wallhavenResolutionWidth = ""; wallhavenResolutionHeight = ""; }; appLauncher = { enableClipboardHistory = false; enableClipPreview = true; position = "center"; pinnedExecs = [ ]; useApp2Unit = false; sortByMostUsed = true; terminalCommand = "xterm -e"; customLaunchPrefixEnabled = false; customLaunchPrefix = ""; viewMode = "list"; showCategories = true; iconMode = "tabler"; ignoreMouseInput = false; }; controlCenter = { position = "close_to_bar_button"; shortcuts = { left = [ { id = "WiFi"; } { id = "Bluetooth"; } { id = "ScreenRecorder"; } { id = "WallpaperSelector"; } ]; right = [ { id = "Notifications"; } { id = "PowerProfile"; } { id = "KeepAwake"; } { id = "NightLight"; } ]; }; cards = [ { enabled = true; id = "profile-card"; } { enabled = true; id = "shortcuts-card"; } { enabled = true; id = "audio-card"; } { enabled = false; id = "brightness-card"; } { enabled = true; id = "weather-card"; } { enabled = true; id = "media-sysmon-card"; } ]; }; systemMonitor = { cpuWarningThreshold = 80; cpuCriticalThreshold = 90; tempWarningThreshold = 80; tempCriticalThreshold = 90; gpuWarningThreshold = 80; gpuCriticalThreshold = 90; memWarningThreshold = 80; memCriticalThreshold = 90; diskWarningThreshold = 80; diskCriticalThreshold = 90; cpuPollingInterval = 3000; tempPollingInterval = 3000; gpuPollingInterval = 3000; enableDgpuMonitoring = false; memPollingInterval = 3000; diskPollingInterval = 3000; networkPollingInterval = 3000; useCustomColors = false; warningColor = ""; criticalColor = ""; diskPath = "/"; externalMonitor = "resources || missioncenter || jdsystemmonitor || corestats || system-monitoring-center || gnome-system-monitor || plasma-systemmonitor || mate-system-monitor || ukui-system-monitor || deepin-system-monitor || pantheon-system-monitor"; }; dock = { enabled = true; displayMode = "auto_hide"; backgroundOpacity = 1; floatingRatio = 1; size = 1; onlySameOutput = true; monitors = [ ]; pinnedApps = [ ]; colorizeIcons = false; pinnedStatic = false; inactiveIndicators = false; deadOpacity = 0.6; animationSpeed = 1; }; network = { wifiEnabled = true; }; sessionMenu = { enableCountdown = true; countdownDuration = 10000; position = "center"; showHeader = true; largeButtonsStyle = false; showNumberLabels = true; powerOptions = [ { action = "lock"; enabled = true; } { action = "suspend"; enabled = true; } { action = "hibernate"; enabled = true; } { action = "reboot"; enabled = true; } { action = "logout"; enabled = true; } { action = "shutdown"; enabled = true; } ]; }; notifications = { enabled = true; monitors = [ ]; location = "top_right"; overlayLayer = true; backgroundOpacity = 1; respectExpireTimeout = false; lowUrgencyDuration = 3; normalUrgencyDuration = 8; criticalUrgencyDuration = 15; enableKeyboardLayoutToast = true; saveToHistory = { low = true; normal = true; critical = true; }; sounds = { enabled = false; volume = 0.5; separateSounds = false; criticalSoundFile = ""; normalSoundFile = ""; lowSoundFile = ""; excludedApps = "discord,firefox,chrome,chromium,edge"; }; }; osd = { enabled = true; location = "top_right"; autoHideMs = 2000; overlayLayer = true; backgroundOpacity = 1; enabledTypes = [ 0 1 2 4 ]; monitors = [ ]; }; audio = { volumeStep = 5; volumeOverdrive = false; cavaFrameRate = 30; visualizerType = "linear"; mprisBlacklist = [ ]; preferredPlayer = ""; externalMixer = "pwvucontrol || pavucontrol"; }; brightness = { brightnessStep = 5; enforceMinimum = true; enableDdcSupport = false; }; colorSchemes = { useWallpaperColors = false; predefinedScheme = "Noctalia (default)"; darkMode = true; schedulingMode = "off"; manualSunrise = "06:30"; manualSunset = "18:30"; matugenSchemeType = "scheme-fruit-salad"; generateTemplatesForPredefined = true; }; templates = { gtk = false; qt = false; kcolorscheme = false; alacritty = false; kitty = false; ghostty = false; foot = false; wezterm = false; fuzzel = false; discord = false; pywalfox = false; vicinae = false; walker = false; code = false; spicetify = false; telegram = false; cava = false; yazi = false; emacs = false; niri = false; hyprland = false; mango = false; zed = false; helix = false; enableUserTemplates = false; }; nightLight = { enabled = false; forced = false; autoSchedule = true; nightTemp = "4000"; dayTemp = "6500"; manualSunrise = "06:30"; manualSunset = "18:30"; }; hooks = { enabled = false; wallpaperChange = ""; darkModeChange = ""; screenLock = ""; screenUnlock = ""; performanceModeEnabled = ""; performanceModeDisabled = ""; }; desktopWidgets = { enabled = false; gridSnap = false; monitorWidgets = [ ]; }; }; }; };}