How to Configure Hyprland Autostart Applications: A Complete Guide

Hyprland launches autostart applications through the exec-once directive in ~/.config/hypr/hyprland.conf, which the CExecutor class processes exactly once during compositor initialization via src/config/supplementary/executor/Executor.cpp.

When the hyprwm/Hyprland compositor starts, it reads your configuration file and executes designated commands automatically. This mechanism allows you to configure Hyprland autostart applications such as status bars, wallpaper daemons, and background services without manual intervention each session.

Understanding the exec-once Mechanism

The autostart system centers on the Executor subsystem located in src/config/supplementary/executor/Executor.cpp. The CExecutor class maintains two private vectors—m_execOnce and m_execShutdown—that store commands parsed from your configuration file.

During Hyprland's initialization sequence, the method CExecutor::applyExecOnce() iterates over the m_execOnce vector and spawns each command using spawn() (which ultimately performs a fork/exec system call). Because the executor clears this vector immediately after the first execution, these commands never run again until you restart the compositor entirely.

According to the Hyprland source code, the execution flow follows this path:

  1. Config parser encounters exec-once = command
  2. Command string pushes to CExecutor::m_execOnce
  3. Startup triggers applyExecOnce()
  4. Each entry spawns via spawn() or spawnWithRules()
  5. Vector clears, preventing re-execution

Basic Configuration Syntax

Add exec-once entries to your ~/.config/hypr/hyprland.conf file. Each line defines one autostart command:


# ~/.config/hypr/hyprland.conf

# Autostart a status bar

exec-once = waybar

# Start a compositor-friendly clipboard manager

exec-once = cliphist daemon

# Launch wallpaper daemon

exec-once = hyprpaper

# Execute a custom setup script

exec-once = $HOME/.config/hypr/autostart.sh

Place these directives at the top level of your configuration file, outside of any category blocks. The parser identifies lines beginning with exec-once and immediately routes them to the executor subsystem.

Advanced Usage and Environment Variables

You can chain multiple commands using logical operators or subshells when you need complex startup sequences:


# Chain commands with && (subsequent only runs if previous succeeds)

exec-once = sh -c 'nm-applet & volumeicon && picom --experimental-backends'

# Group related services in a single subshell

exec-once = sh -c 'nm-applet & 
                volumeicon &
                xrandr --output eDP-1 --primary --auto'

Environment variable expansion occurs before execution. The helper functions in src/helpers/MiscFunctions.cpp handle the expansion of $HOME, $DISPLAY, $USER, and other variables defined in your environment. This ensures that paths and settings resolve correctly regardless of where you launch Hyprland from.

exec-once vs exec: Key Differences

Hyprland offers two distinct execution directives with different persistence behaviors:

  • exec-once: Runs only during the initial compositor startup. According to the implementation in Executor.cpp, the executor runs applyExecOnce() exactly once and clears the m_execOnce vector afterward. Reloading your configuration with hyprctl reload does not re-trigger these commands.

  • exec: Executes commands immediately when parsed, typically used within keybind definitions. These run every time the binding triggers or the configuration reloads.

If you need applications to restart when you reload your configuration, use exec within a keybind or script rather than exec-once.

Summary

  • Location: Define autostart applications in ~/.config/hypr/hyprland.conf using the exec-once directive.
  • Implementation: The CExecutor class in src/config/supplementary/executor/Executor.cpp stores commands in the m_execOnce vector and executes them via applyExecOnce() during startup.
  • Behavior: Commands run exactly once per compositor session; configuration reloads do not re-execute them.
  • Variables: Environment variables expand automatically through helpers in src/helpers/MiscFunctions.cpp.
  • Complex sequences: Use sh -c with & or && operators to chain multiple applications.

Frequently Asked Questions

Why don't my autostart applications restart when I reload Hyprland's config?

The exec-once directive intentionally prevents re-execution during configuration reloads. As implemented in src/config/supplementary/executor/Executor.cpp, the CExecutor::applyExecOnce() method clears the m_execOnce vector immediately after spawning commands during the initial startup. This design ensures that long-running background services do not spawn duplicate processes when you tweak keybindings or window rules.

Can I use environment variables like $HOME in exec-once commands?

Yes. Hyprland expands environment variables before execution through helper functions located in src/helpers/MiscFunctions.cpp. You can safely use $HOME, $USER, $DISPLAY, and custom variables defined in your shell profile. For example: exec-once = $HOME/.local/bin/custom-script.sh resolves correctly at startup.

How do I run multiple commands on startup without creating a separate script?

Use a subshell with sh -c and background operators. Wrap your command sequence in single quotes and separate individual programs with & (background) or && (conditional). For instance: exec-once = sh -c 'waybar & cliphist daemon & hyprpaper' starts all three services simultaneously. This approach keeps your hyprland.conf self-contained while launching complex application groups.

What is the difference between exec and exec-once in Hyprland?

exec-once runs exclusively during the compositor's initial startup sequence, stored in CExecutor::m_execOnce and triggered once via applyExecOnce(). exec executes immediately when parsed, typically within keybind handlers or during configuration reloads. Use exec-once for one-time initialization tasks like starting panels or daemons, and reserve exec for commands you want to trigger via hotkeys or run on every config reload.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →