Skip to content

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.

To install Noctalia, you need to add a flake input and install the package.

Add the required inputs to your flake configuration:

flake.nix
{
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.

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:

noctalia.nix
{ 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 ..


If you have home manager installed, you can configure your Noctalia shell in Nix.

To configure Noctalia settings, you can use the Noctalia home manager module:

noctalia.nix
{ 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 = "Network";
}
{
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.
};
};
}

We don’t have extensive documentation of Noctalia’s configuration options; however, you can see an up-to-date list of configuration defaults.

Additionally, since ~/.config/noctalia/settings.json is now a read-only symlink, you can get the latest (or GUI-modified) settings via: Open Settings Panel -> General -> Copy Settings or by running noctalia-shell ipc call state all | jq .settings, then use them to update your Nix config for a permanent change.

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:

noctalia.nix
{ 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.
};
};
}

The user-templates option allows you to define custom 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:

noctalia.nix
{ pkgs, inputs, ... }:
{
home-manager.users.drfoobar = {
# ...
programs.noctalia-shell = {
enable = true;
settings = {
templates = {
enableUserTemplates = true;
};
};
user-templates = ''
[config]
# General template settings
[templates.myapp]
input_path = "~/.config/noctalia/templates/myapp.css"
output_path = "~/.config/myapp/theme.css"
post_hook = "myapp --reload-theme"
'';
};
};
}

As a path:

noctalia.nix
{ 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:

noctalia.nix
{ pkgs, inputs, ... }:
{
home-manager.users.drfoobar = {
# ...
programs.noctalia-shell = {
enable = true;
settings = {
templates = {
enableUserTemplates = true;
};
};
user-templates = {
config = {
# General template settings
};
templates = {
myapp = {
input_path = "~/.config/noctalia/templates/myapp.css";
output_path = "~/.config/myapp/theme.css";
post_hook = "myapp --reload-theme";
};
};
};
};
};
}

You can configure plugins in a declarative way. If an enabled plugin isn’t installed in the plugin directory, Noctalia will automatically install it when starts up.

noctalia.nix
{ pkgs, inputs, ... }:
{
home-manager.users.drfoobar = {
# import the home manager module
imports = [
inputs.noctalia.homeModules.default
];
# configure options
programs.noctalia-shell = {
enable = true;
plugins = {
sources = [
{
enabled = true;
name = "Official Noctalia Plugins";
url = "https://github.com/noctalia-dev/noctalia-plugins";
}
];
states = {
catwalk = {
enabled = true;
sourceUrl = "https://github.com/noctalia-dev/noctalia-plugins";
};
};
version = 2;
};
# this may also be a string or a path to a JSON file.
pluginSettings = {
catwalk = {
minimumThreshold = 25;
hideBackground = true;
};
# this may also be a string or a path to a JSON file.
};
};
};
}

Wallpapers are configured in ~/.cache/noctalia/wallpapers.json. You can set them declaratively:

noctalia.nix
{ 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";
};
};
};
};
}

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:

niri.nix
{ 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:

niri.nix
{ 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
};
};
};
};
}

The Noctalia shell can now be run in two ways: manually or using a systemd service

To run Noctalia using the flake, run:

Terminal window
noctalia-shell

With the Niri flake, you can then spawn Noctalia on startup like this:

niri.nix
{ pkgs, inputs, ... }:
{
# ...
home-manager.users.drfoobar = {
# ...
programs.niri = {
package = niri;
settings = {
# ...
spawn-at-startup = [
{
command = [
"noctalia-shell"
];
}
];
};
};
};
}

You can setup the systemd service via the NixOS module or the Home Manager module. If you configure Noctalia Shell with Home Manager, use the Home Manager module—it’s the better choice. Don’t enable the service in both modules at once, since they create services with the same name; which one runs is unpredictable (usually the Home Manager one).

Import the Noctalia NixOS modules and enable the service:

noctalia.nix
{ 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:

noctalia.nix
{ pkgs, inputs, ... }:
{
# ...
services.noctalia-shell = {
enable = true;
target = "my-hyprland-session.target";
};
}

This target depends on how you configure your Hyprland session systemd service.

Import the Noctalia Home Manager modules and enable the service:

noctalia.nix
{ 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.


To add support for events in the calendar via evolution-data-server.

  1. Enable the evolution-data-server:
services.gnome.evolution-data-server.enable = true;
  1. Override the Noctalia package:
(pkgs.noctalia-shell.override { calendarSupport = true; })

or

(inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default.override { calendarSupport = true; })

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:

noctalia.nix
{ pkgs, inputs, ... }:
{
home-manager.users.drfoobar = {
imports = [
inputs.noctalia.homeModules.default
];
programs.noctalia-shell = {
enable = true;
settings = {
settingsVersion = 0;
bar = {
barType = "simple";
position = "top";
monitors = [ ];
density = "default";
showOutline = false;
showCapsule = true;
capsuleOpacity = 1;
capsuleColorKey = "none";
backgroundOpacity = 0.93;
useSeparateOpacity = false;
floating = false;
marginVertical = 4;
marginHorizontal = 4;
frameThickness = 8;
frameRadius = 12;
outerCorners = true;
hideOnOverview = false;
displayMode = "always_visible";
autoHideDelay = 500;
autoShowDelay = 150;
widgets = {
left = [
{
id = "Launcher";
}
{
id = "Clock";
}
{
id = "SystemMonitor";
}
{
id = "ActiveWindow";
}
{
id = "MediaMini";
}
];
center = [
{
id = "Workspace";
}
];
right = [
{
id = "Tray";
}
{
id = "NotificationHistory";
}
{
id = "Battery";
}
{
id = "Volume";
}
{
id = "Brightness";
}
{
id = "ControlCenter";
}
];
};
screenOverrides = [ ];
};
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;
lockScreenAnimations = false;
lockOnSuspend = true;
showSessionButtonsOnLockScreen = true;
showHibernateOnLockScreen = false;
enableShadows = true;
shadowDirection = "bottom_right";
shadowOffsetX = 2;
shadowOffsetY = 3;
language = "";
allowPanelsOnScreenWithoutBar = true;
showChangelogOnStartup = true;
telemetryEnabled = false;
enableLockScreenCountdown = true;
lockScreenCountdownDuration = 10000;
autoStartAuth = false;
allowPasswordWithFprintd = false;
clockStyle = "custom";
clockFormat = "hh\nmm";
lockScreenMonitors = [ ];
lockScreenBlur = 0;
lockScreenTint = 0;
keybinds = {
keyUp = [
"Up"
];
keyDown = [
"Down"
];
keyLeft = [
"Left"
];
keyRight = [
"Right"
];
keyEnter = [
"Return"
];
keyEscape = [
"Esc"
];
keyRemove = [
"Del"
];
};
};
ui = {
fontDefault = "";
fontFixed = "";
fontDefaultScale = 1;
fontFixedScale = 1;
tooltipsEnabled = true;
panelBackgroundOpacity = 0.93;
panelsAttachedToBar = true;
settingsPanelMode = "attached";
wifiDetailsViewMode = "grid";
bluetoothDetailsViewMode = "grid";
networkPanelView = "wifi";
bluetoothHideUnnamedDevices = false;
boxBorderEnabled = false;
};
location = {
name = "Tokyo";
weatherEnabled = true;
weatherShowEffects = true;
useFahrenheit = false;
use12hourFormat = false;
showWeekNumberInCalendar = false;
showCalendarEvents = true;
showCalendarWeather = true;
analogClockInCalendar = false;
firstDayOfWeek = -1;
hideWeatherTimezone = false;
hideWeatherCityName = false;
};
calendar = {
cards = [
{
enabled = true;
id = "calendar-header-card";
}
{
enabled = true;
id = "calendar-month-card";
}
{
enabled = true;
id = "weather-card";
}
];
};
wallpaper = {
enabled = true;
overviewEnabled = false;
directory = "";
monitorDirectories = [ ];
enableMultiMonitorDirectories = false;
showHiddenFiles = false;
viewMode = "single";
setWallpaperOnAllMonitors = true;
fillMode = "crop";
fillColor = "#000000";
useSolidColor = false;
solidColor = "#1a1a2e";
automationEnabled = false;
wallpaperChangeMode = "random";
randomIntervalSec = 300;
transitionDuration = 1500;
transitionType = "random";
skipStartupTransition = false;
transitionEdgeSmoothness = 0.05;
panelPosition = "follow_bar";
hideWallpaperFilenames = false;
overviewBlur = 0.4;
overviewTint = 0.6;
useWallhaven = false;
wallhavenQuery = "";
wallhavenSorting = "relevance";
wallhavenOrder = "desc";
wallhavenCategories = "111";
wallhavenPurity = "100";
wallhavenRatios = "";
wallhavenApiKey = "";
wallhavenResolutionMode = "atleast";
wallhavenResolutionWidth = "";
wallhavenResolutionHeight = "";
sortOrder = "name";
favorites = [ ];
};
appLauncher = {
enableClipboardHistory = false;
autoPasteClipboard = false;
enableClipPreview = true;
clipboardWrapText = true;
clipboardWatchTextCommand = "wl-paste --type text --watch cliphist store";
clipboardWatchImageCommand = "wl-paste --type image --watch cliphist store";
position = "center";
pinnedApps = [ ];
useApp2Unit = false;
sortByMostUsed = true;
terminalCommand = "alacritty -e";
customLaunchPrefixEnabled = false;
customLaunchPrefix = "";
viewMode = "list";
showCategories = true;
iconMode = "tabler";
showIconBackground = false;
enableSettingsSearch = true;
enableWindowsSearch = true;
enableSessionSearch = true;
ignoreMouseInput = false;
screenshotAnnotationTool = "";
overviewLayer = false;
density = "default";
};
controlCenter = {
position = "close_to_bar_button";
diskPath = "/";
shortcuts = {
left = [
{
id = "Network";
}
{
id = "Bluetooth";
}
{
id = "WallpaperSelector";
}
{
id = "NoctaliaPerformance";
}
];
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;
swapWarningThreshold = 80;
swapCriticalThreshold = 90;
diskWarningThreshold = 80;
diskCriticalThreshold = 90;
diskAvailWarningThreshold = 20;
diskAvailCriticalThreshold = 10;
batteryWarningThreshold = 20;
batteryCriticalThreshold = 5;
enableDgpuMonitoring = false;
useCustomColors = false;
warningColor = "";
criticalColor = "";
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;
position = "bottom";
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;
airplaneModeEnabled = false;
bluetoothRssiPollingEnabled = false;
bluetoothRssiPollIntervalMs = 60000;
wifiDetailsViewMode = "grid";
bluetoothDetailsViewMode = "grid";
bluetoothHideUnnamedDevices = false;
disableDiscoverability = false;
};
sessionMenu = {
enableCountdown = true;
countdownDuration = 10000;
position = "center";
showHeader = true;
largeButtonsStyle = true;
largeButtonsLayout = "single-row";
powerOptions = [
{
action = "lock";
enabled = true;
keybind = "1";
}
{
action = "suspend";
enabled = true;
keybind = "2";
}
{
action = "hibernate";
enabled = true;
keybind = "3";
}
{
action = "reboot";
enabled = true;
keybind = "4";
}
{
action = "logout";
enabled = true;
keybind = "5";
}
{
action = "shutdown";
enabled = true;
keybind = "6";
}
];
};
notifications = {
enabled = true;
density = "default";
monitors = [ ];
location = "top_right";
overlayLayer = true;
backgroundOpacity = 1;
respectExpireTimeout = false;
lowUrgencyDuration = 3;
normalUrgencyDuration = 8;
criticalUrgencyDuration = 15;
saveToHistory = {
low = true;
normal = true;
critical = true;
};
sounds = {
enabled = false;
volume = 0.5;
separateSounds = false;
criticalSoundFile = "";
normalSoundFile = "";
lowSoundFile = "";
excludedApps = "discord,firefox,chrome,chromium,edge";
};
enableMediaToast = false;
enableKeyboardLayoutToast = true;
enableBatteryToast = true;
};
osd = {
enabled = true;
location = "top_right";
autoHideMs = 2000;
overlayLayer = true;
backgroundOpacity = 1;
enabledTypes = [
0
1
2
];
monitors = [ ];
};
audio = {
volumeStep = 5;
volumeOverdrive = false;
cavaFrameRate = 30;
visualizerType = "linear";
mprisBlacklist = [ ];
preferredPlayer = "";
volumeFeedback = false;
};
brightness = {
brightnessStep = 5;
enforceMinimum = true;
enableDdcSupport = false;
};
colorSchemes = {
useWallpaperColors = false;
predefinedScheme = "Noctalia (default)";
darkMode = true;
schedulingMode = "off";
manualSunrise = "06:30";
manualSunset = "18:30";
generationMethod = "tonal-spot";
monitorForColors = "";
};
templates = {
activeTemplates = [ ];
enableUserTheming = 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 = "";
startup = "";
session = "";
};
plugins = {
autoUpdate = false;
};
desktopWidgets = {
enabled = false;
gridSnap = false;
monitorWidgets = [ ];
};
};
};
};
}