How configuration works
Noctalia can be configured in two ways: files you write yourself, and settings the app saves for you.
For most people, the important rule is simple: put your own configuration in ~/.config/noctalia/. If something changed in the GUI and now seems to ignore your file, check ~/.local/state/noctalia/settings.toml.
The two layers
Section titled “The two layers”Your hand-written config lives in:
$NOCTALIA_CONFIG_HOME/noctalia/$XDG_CONFIG_HOME/noctalia/- or
~/.config/noctalia/
Noctalia reads every *.toml file in that folder, sorts them alphabetically, and merges them into one config. A single config.toml is the easiest setup:
[theme]mode = "dark"
[bar.default]position = "top"You can also split things up if you like tidy dotfiles:
~/.config/noctalia/├── bar.toml├── theme.toml└── widgets.tomlGUI-managed overrides live in:
$NOCTALIA_STATE_HOME/noctalia/settings.toml$XDG_STATE_HOME/noctalia/settings.toml- or
~/.local/state/noctalia/settings.toml
Noctalia writes this file when you change settings through the UI, setup flows, IPC-backed controls, and other runtime actions that need to persist. If the file is a symbolic link, Noctalia writes through to the link target and keeps the link in place.
NOCTALIA_CONFIG_HOME and NOCTALIA_STATE_HOME have the same “home root” shape as the XDG variables. For example, NOCTALIA_CONFIG_HOME=/tmp/profile reads /tmp/profile/noctalia/. Use these Noctalia-specific variables when you want a separate shell profile without changing the environment inherited by apps launched from Noctalia.
Including extra files
Section titled “Including extra files”Automatic loading only sees *.toml files sitting directly in the config folder. To pull in files from subdirectories, load a specific file, or control load order without renaming files, add an [include] table:
[include]files = [ "widgets/", # a directory: every *.toml inside it (sorted, non-recursive) "bars/top.toml", # a single file "~/.config/shared/base.toml", # ~ , $VAR and ${VAR} are expanded]
# the rest of this file's settings go here as usual[theme]mode = "dark"Each entry is either a directory (which loads every *.toml directly inside it, sorted alphabetically) or a single file. Relative paths resolve against the directory of the file doing the including, so a file in profiles/work.toml can reach a shared bundle with "../widgets/". Paths starting with ~, or containing $VAR / ${VAR}, are expanded.
The including file wins. Included files are merged first, as a reusable base, and then the file’s own settings are layered on top. So a value you set directly in config.toml overrides the same value pulled in from an include:
[include]files = ["bars/base.toml"] # base.toml sets bar.top.thickness = 30
[bar.top]thickness = 40 # this wins - the bar ends up 40Includes can nest (an included file can include more files), and each file is loaded at most once - if two files include the same file, it is merged once and a cycle is detected and skipped rather than looping forever.
Switching profiles
Section titled “Switching profiles”By default, every *.toml in the config folder still loads automatically alongside your includes. If you keep alternative setups in the root that should not all load at once - say profile_a.toml and profile_b.toml - set autoload = false in your entry file. Then only the file(s) that set it (plus whatever they include) load, and the other root files are ignored:
[include]autoload = falsefiles = ["profiles/work.toml"]autoload only has an effect in a file loaded directly from the config folder; it is ignored in included files. [include] is honored in your config files only - it has no effect in the app-managed settings.toml.
Which value wins?
Section titled “Which value wins?”Noctalia loads configuration in this order:
- Built-in defaults
- Your
*.tomlfiles in the resolved config directory - for each file, anything it pulls in via[include]first, then the file’s own settings on top - GUI-managed overrides in the resolved state directory’s
settings.toml
Because settings.toml loads last, it wins when it contains the same setting as your hand-written config layer.
When Settings writes a value that matches the parsed value from the lower layers, Noctalia removes that redundant key
instead of keeping it as a GUI override.
Where should I edit?
Section titled “Where should I edit?”Use ~/.config/noctalia/ for curated config: the things you want to keep in dotfiles, copy to another machine, or manage declaratively.
Treat ~/.local/state/noctalia/settings.toml as an app-managed override file. It is useful to inspect when debugging GUI changes, and safe to delete when you want to clear those overrides. Keeping it outside ~/.config also lets the GUI save changes when your config directory is read-only, for example on NixOS. Support reports include config sources and settings.toml, but omit state.toml contents because they can contain private runtime data.
Both layers are watched for changes and hot-reloaded. If neither layer exists, Noctalia uses its built-in defaults.
Automatic configuration migrations
Section titled “Automatic configuration migrations”When a release changes the shape of a setting, Noctalia migrates old values before parsing them so the running shell
keeps the intended behavior. The app-owned settings.toml is upgraded once and stamped with an internal
config_version; Noctalia manages that marker and excludes it from exported user config.
Files under ~/.config/noctalia/ are never rewritten. Values that need migration are normalized temporarily on every
load, and Settings keeps a warning visible until you update the source TOML. The warning and notification identify the
source file, line, column, and exact legacy key to edit. Noctalia sends the notification when it first finds an affected
key, when a new affected key appears, and every three days while affected values remain.
Run the validator to list every affected key, its source location, and its canonical replacement:
noctalia config validateNoctalia can keep using normalized values while you update a file, but migration warnings are intentionally not permanent compatibility promises. Treat them as required config maintenance.
File locations
Section titled “File locations”Where Noctalia keeps everything, by purpose:
| What | Where | Purpose |
|---|---|---|
| Your config | ~/.config/noctalia/config.toml | hand-written / declarative - the base layer |
| GUI overrides | ~/.local/state/noctalia/settings.toml | written by Settings; wins over your config |
| Internal UI state | ~/.local/state/noctalia/state.toml | app-managed non-secret state and last-used values |
| Calendar credentials | Desktop Secret Service or an explicit CalDAV password file | CalDAV passwords and Google refresh tokens |
| Encrypted storage key | Desktop Secret Service or an explicit key file | master key for encrypted clipboard history and calendar events |
| Calendar event cache | $XDG_CACHE_HOME/noctalia/calendar/events.enc | encrypted last-known-good events |
| Custom palettes | ~/.config/noctalia/palettes/ | your own color palette files |
| Local plugins | ~/.local/share/noctalia/plugins/ | plugins you install or place by hand |
| Plugin source repos | ~/.local/state/noctalia/plugins/sources/ | git-source repo caches, re-fetchable |
| Exported plugin files | ~/.local/state/noctalia/plugins/materialized/ | runtime files exported from git sources |
| Community palettes / templates | ~/.local/state/noctalia/community-*/ | downloaded catalogs, re-fetchable |
It comes down to three storage owners:
- Yours -
~/.config/noctalia/(settings you write) and~/.local/share/noctalia/(plugins you install). - Noctalia’s -
~/.local/state/noctalia/(GUI overrides, UI state, plugin repo caches, exported plugin files, and downloaded catalogs). - Credential provider’s - durable calendar credentials and the encrypted storage master key managed by Secret Service, or explicit credential/key files managed by an external provisioner such as agenix. Deleting Noctalia’s state directory does not remove them.
Every path honors the relevant standard XDG_CONFIG_HOME / XDG_STATE_HOME / XDG_DATA_HOME / XDG_CACHE_HOME
variable (and the NOCTALIA_CONFIG_HOME / NOCTALIA_STATE_HOME / NOCTALIA_DATA_HOME overrides where applicable).
Exporting config
Section titled “Exporting config”Export the merged user config from the command line:
noctalia config export > noctalia-config.tomlExport the full effective config, including built-in defaults:
noctalia config export full > noctalia-full-config.tomlExport stops with an error (and writes nothing) if a config file fails to parse or an [include] points at a file that does not exist, so a broken config never produces a misleading partial export. (The running shell is more forgiving: it loads what it can and surfaces the problem as a notification.)
Because export writes TOML to stdout, you can pipe it into TOML-aware query tools. For example, with
yq:
noctalia config export full | yq -p toml -r '.theme.mode'noctalia config export full | yq -p toml -r '.shell.offline_mode'noctalia config export full | yq -p toml '.bar.default'If you prefer normal jq filters, convert the TOML stream to JSON first:
noctalia config export full | yq -p toml -o json '.' | jq -r '.theme.mode'The Settings actions menu includes Export Config…. It opens a chooser with two export modes:
- Merged User Config is recommended for dotfiles. It merges your explicit config files and GUI-managed overrides into one TOML file, while leaving built-in defaults implicit.
- Full Effective Config exports the active config snapshot, including built-in defaults. Use it for inspection or sharing an exact state, but avoid treating it as your long-term curated config because it pins defaults that could otherwise evolve.
Validating your configuration
Section titled “Validating your configuration”Run the validator to catch problems before they silently take effect:
noctalia config validateWith no argument it checks the merged configuration exactly as the shell loads it: every *.toml in ~/.config/noctalia/ (or $NOCTALIA_CONFIG_HOME), then the settings.toml overrides in ~/.local/state/noctalia/. Pass a directory to validate just that directory’s *.toml files instead:
noctalia config validate ./my-config-dirPass a file to validate only that TOML file, without scanning default locations or merging settings.toml. This is useful for generated configs, including NixOS-managed config files:
noctalia config validate ./config.tomlEvery diagnostic is prefixed with the file, line, and column it came from, followed by the dotted config path:
WARN /home/you/.config/noctalia/bar.toml:14:10: bar.main.foo: unknown settingERROR /home/you/.config/noctalia/widgets.toml:22:12: widget.clock.timezone: unknown timezone "Europe/Berln"With several config files in play (or settings.toml overriding one of them), the reported file is the one whose definition actually won the merge.
It reports two severities:
- Errors - problems that stop the configuration from loading correctly: TOML syntax errors, values that fail to parse such as an invalid color, invalid cross-field combinations such as a keyboard layout with both its glyph and label hidden, an
[include]whosefilesentry points at a path that does not exist, or a malformed[include]table (autoloadthat is not a boolean,filesthat is not a list of strings). These exit with status1. - Warnings - things the shell loads fine but ignores, adjusts, or migrates in memory: unknown/obsolete sections and settings (misspelled or left over from an older version), values with a canonical replacement, values outside the allowed range (clamped), and invalid enum choices. Warnings are advisory and do not fail the check. Unknown widget and desktop-widget settings are checked against each widget type’s known options.
A config with only warnings still prints ✓ Config is valid and exits 0 (with the warnings listed), so unknown keys won’t break a pre-commit hook or CI step - they’re surfaced as cleanup hints. Only genuine errors exit 1.
The shell log carries the same prefix, and the on-screen config-error notification puts the location in its title:
config.toml:22:12Error: widget.clock.timezone: unknown timezone "Europe/Berln"There the file is shown relative to your config directory (or as a bare file name for settings.toml), so a bad value points straight at the line that set it. When the position cannot be determined, the notification falls back to a Config error title.
Where next?
Section titled “Where next?”- Shell covers global behavior like fonts, scale, shadows, OSD, and keybinds.
- Hooks covers advanced event-driven automation.
- Bars and Widgets cover the top or side bar and everything inside it.
- Dock covers the optional app dock.
- Theme covers theme mode and palette source selection.
- Palette covers color roles, custom palette files, and terminal colors.
- App Theming covers generated themes for other apps.
- Template Reference covers template syntax, tokens, filters, and hooks.
- Wallpaper & backdrop covers wallpapers, per-monitor folders, automation, and overview backdrop.
- Service pages cover audio, brightness, calendar, idle, night light, notifications, and weather.
- IPC lists commands for keybinds, scripts, automation, and hooks.