Automatically throttles background applications on Linux, inspired by macOS App Nap.
When you switch focus to another window, napd puts background apps to sleep: they get lower CPU priority, idle I/O scheduling, and relaxed timer resolution. The moment you bring an app back to the foreground, it is fully restored.
- Monitors window focus via
zwlr_foreign_toplevel_manager_v1(Wayland) - Waits for a configurable grace period before throttling
- Skips apps that are playing audio (tracked via PipeWire)
- Applies a bundle of throttle knobs to background processes and all their children:
- Moves to a CPU-limited cgroup (
cpu.max) - Sets scheduling policy to
SCHED_BATCH - Sets CPU nice to
+19 - Sets I/O priority to
IOPRIO_CLASS_IDLE - Sets timer slack to 2 seconds
- Moves to a CPU-limited cgroup (
- Fully restores all saved state on focus return or daemon shutdown
- Linux with cgroup v2
- Wayland compositor with
zwlr_foreign_toplevel_manager_v1(Sway, Niri, wlroots-based) - PipeWire (for audio bypass)
- Rust toolchain
# Install build dependency
sudo apt install libpipewire-0.3-dev # Debian/Ubuntu
sudo dnf install pipewire-devel # Fedora
sudo apt-get install libpipewire-devel # ALT Linux
# Build and install as a systemd user service
./install.shThe script builds the binary, installs it to /usr/local/bin/napd, and enables the systemd user service.
./uninstall.shConfig file: /etc/napd/config.toml (or override with NAP_CONFIG=/path/to/config.toml)
If the file does not exist, built-in defaults are used.
# Seconds an app must stay in background before throttling begins
grace_period_secs = 5
# Timer slack for background threads (nanoseconds). Max ~4.29s (kernel u32 limit).
bg_timerslack_ns = 2_000_000_000
# Timer slack restored for foreground threads (nanoseconds)
fg_timerslack_ns = 50_000
# Cgroup path relative to /sys/fs/cgroup/
bg_cgroup = "background"
# CPU quota for background cgroup in µs per 100ms period.
# Example: 10000 = 10% of one core. Comment out for unlimited.
# bg_cpu_quota_us = 10000
# App IDs to never throttle (Wayland app_id values)
bypass_app_ids = ["spotify", "org.mozilla.firefox"]# Follow live logs
journalctl --user -u napd -f
# Verbose output
RUST_LOG=debug napd- Wayland only — X11 is not supported
- Process matching uses heuristics (comm, cmdline basename) to map
app_idto PIDs; some apps may not be found - Requires cgroup v2 unified hierarchy for CPU quota enforcement