Sweets
Configuration

Basic Configuration

How Sweets loads, layers, and reloads your Lua configuration.

Sweets is configured in Lua. On startup it loads the packaged defaults first, then layers your user config on top.

Load order

Packaged defaults load first:

/usr/share/sweets/sweets.lua

Or the equivalent sweets/sweets.lua under the Meson install datadir.

Your user config loads next, when present:

$XDG_CONFIG_HOME/sweets/sweets.lua

Falls back to ~/.config/sweets/sweets.lua when XDG_CONFIG_HOME is unset.

User settings layer over the defaults. Binding the same key combo again replaces the default binding.

Either file can pull in more Lua files with sweets.include(...).

Fail-safe behavior

A broken config never crashes the compositor.

  • Missing user file — Sweets uses the packaged defaults as-is.
  • No bindings anywhere — Sweets falls back to a tiny emergency C binding set so the compositor stays controllable.
  • Error in a Lua file — Sweets logs it, keeps the previous config, and shows the error on screen.

Error reporting

When a config fails to load, Sweets shows a red bar across the top of every monitor with the failing file, line, and message. This covers syntax errors, unknown fields, and invalid values. The compositor keeps running on the last good config.

The bar clears itself as soon as a later edit reloads cleanly. You can also dismiss it by clicking any monitor's bar or using the dismiss_error binding. Both clear every monitor at once. A dismissed bar returns on the next failed reload.

The bar is drawn by sweetnag, a small helper installed alongside the compositor. Preview it with echo "example error" | sweetnag. Its colors and font are configurable through sweets.notify{ ... }.

Automatic reload

Sweets watches the packaged defaults, your user config, and every included file. Saving, creating, atomically replacing, or deleting any of them triggers a fail-safe reload after a short debounce.

Manual reload is always available with MOD + Shift + R or sweetctl reload.

The sweets table

The global sweets table is available to your config script.

CallConfigures
sweets.general{ ... }Modifier key, background, workspace and cross-monitor behavior
sweets.layout{ ... }Master/stack tiling, gaps, and window borders
sweets.notify{ ... }Colors and font of the config-error bar
sweets.keyboard{ ... } / sweets.cursor{ ... }Keyboard repeat and numlock, cursor size and theme
sweets.pointer{ ... }Automatic pointer-follow after focus and workspace changes
sweets.input(...)libinput pointer settings, globally or per-device
sweets.monitor(...)Output rules — resolution, scale, position, transform
sweets.workspace(...)Pin workspaces to specific monitors
sweets.rule({ ... })Initial placement and behavior for matching windows
sweets.env(...)Export environment variables to launched commands
sweets.exec_once(...)Start a program once per session
sweets.bind(...)Key bindings and media keys
sweets.bindswitch(...)Commands for lid, tablet-mode, and keypad switches
Mouse bindingsBuilt-in MOD + drag to move and resize
sweets.include(...)Load another Lua file

The Lua environment

Config code runs in a sandboxed Lua 5.4 environment. The compositor is security-sensitive, so sweets.lua gets the language, not the operating system.

Available — the base library except protected calls, plus string, table, math, utf8, and a reduced os with os.getenv, os.time, os.date, os.clock, and os.difftime.

Not availablepcall, xpcall, io, package / require, debug, dofile, loadfile, load, and the rest of os. Protected calls are omitted so a config cannot catch a resource-limit error and continue without its guard.

Instead, use:

Every numeric option must be a finite number. Values like 0/0, math.huge, and -math.huge are rejected.

Loops and helper functions are fine — the full language is there. As a last defense, each config load is limited to 10 million Lua instructions and 16 MiB of Lua-managed memory. Exceeding either is treated like any other config error.

On this page