How to Add Hyprland to an Existing Arch Linux + GDM Setup (With Dotfiles and GNU Stow)

7/24/2025

I recently added Hyprland, a dynamic Wayland compositor, to my Arch Linux setup without removing GNOME. I also wanted to manage all my Hyprland-related config files using my dotfiles repo, and I used stow to keep things neat and modular.

This guide walks through:

  • Installing Hyprland and its dependencies
  • Keeping GNOME (via GDM)
  • Managing config files via GNU Stow and a local dotfiles repo

πŸ›  Prerequisites

  • You’re already running Arch Linux
  • You have GDM (GNOME Display Manager) installed
  • You manage dotfiles using GNU Stow
  • Your dotfiles live at ~/dotfiles

🧩 Step 1: Install Hyprland + Essentials

Install Hyprland and some handy tools:

yay -S hyprland waybar swayosd-git \
    xdg-desktop-portal-hyprland hyprpaper \
    kitty dolphin thunar walker-bin nwg-look \
    brightnessctl pavucontrol

πŸŽ› Step 2: Add Hyprland to GDM

Create a Wayland session file for GDM to recognize:

sudo tee /usr/share/wayland-sessions/hyprland.desktop > /dev/null <<EOF
[Desktop Entry]
Name=Hyprland
Comment=Hyprland Wayland Compositor
Exec=Hyprland
Type=Application
DesktopNames=Hyprland
EOF

βœ… This adds "Hyprland" to the GDM login screen dropdown.

πŸ“ Step 3: Organize Configs in Your Dotfiles

I'll assume your dotfiles are organized like this:

~/dotfiles/
  hypr/
    .config/hypr/hyprland.conf
  waybar/
    .config/waybar/config.jsonc
    .config/waybar/style.css
  swayosd/
    .config/swayosd/config.toml
  hyprpaper/
    .config/hypr/hyprpaper.conf

Tip: This structure ensures stow hypr will create ~/.config/hypr/... etc.

Example swayosd/config.toml:

[swayosd]
volume-step = 5
brightness-step = 5

Example hyprland.conf for starters:

$mod = SUPER

bind = ,XF86AudioRaiseVolume, exec, swayosd-client --output-volume +5
bind = ,XF86AudioLowerVolume, exec, swayosd-client --output-volume -5
bind = ,XF86AudioMute, exec, swayosd-client --output-volume mute
bind = ,XF86MonBrightnessUp, exec, swayosd-client --brightness +5
bind = ,XF86MonBrightnessDown, exec, swayosd-client --brightness -5

# Load Walker launcher with Super+D
bind = $mod, D, exec, walker

# Reload config with Super+R
bind = $mod, R, exec, hyprctl reload

# Application bindings
$terminal = uwsm app -- kitty
$browser = flatpak run com.google.Chrome
$webapp = $browser --app

bind = SUPER, return, exec, $terminal
bind = SUPER, F, exec, uwsm app -- nautilus --new-window
bind = SUPER, B, exec, $browser
bind = SUPER, M, exec, uwsm app -- spotify
bind = SUPER, N, exec, $terminal -e nvim
bind = SUPER, T, exec, $terminal -e btop
bind = SUPER SHIFT, D, exec, $terminal -e lazydocker
bind = SUPER, G, exec, uwsm app -- signal-desktop
bind = SUPER, O, exec, uwsm app -- obsidian -disable-gpu
bind = SUPER, slash, exec, uwsm app -- 1password

bind = SUPER, A, exec, $webapp="https://chatgpt.com"
bind = SUPER SHIFT, A, exec, $webapp="https://grok.com"
bind = SUPER, Y, exec, $webapp="https://youtube.com/"

# Switch to workspace 1-5
bind = $mod, 1, workspace, 1
bind = $mod, 2, workspace, 2
bind = $mod, 3, workspace, 3
bind = $mod, 4, workspace, 4
bind = $mod, 5, workspace, 5

# Move focused window to workspace 1-5
bind = SUPER_SHIFT, 1, movetoworkspace, 1
bind = SUPER_SHIFT, 2, movetoworkspace, 2
bind = SUPER_SHIFT, 3, movetoworkspace, 3
bind = SUPER_SHIFT, 4, movetoworkspace, 4
bind = SUPER_SHIFT, 5, movetoworkspace, 5

# Navigate between windows (focus)
bind = $mod, h, movefocus, l
bind = $mod, l, movefocus, r
bind = $mod, k, movefocus, u
bind = $mod, j, movefocus, d

# Control tiling
bind = SUPER, J, togglesplit, # dwindle
bind = SUPER, P, pseudo, # dwindle
bind = SUPER, V, togglefloating,
bind = SHIFT, F11, fullscreen, 0

# Swap active window with the one next to it with mainMod + SHIFT + arrow keys
bind = SUPER SHIFT, h, swapwindow, l
bind = SUPER SHIFT, l, swapwindow, r
bind = SUPER SHIFT, k, swapwindow, u
bind = SUPER SHIFT, j, swapwindow, d

# Resize active window
bind = SUPER, minus, resizeactive, -100 0
bind = SUPER, equal, resizeactive, 100 0
bind = SUPER SHIFT, minus, resizeactive, 0 -100
bind = SUPER SHIFT, equal, resizeactive, 0 100

# Scroll through existing workspaces with mainMod + scroll
bind = SUPER, mouse_down, workspace, e+1
bind = SUPER, mouse_up, workspace, e-1

# Move/resize windows with mainMod + LMB/RMB and dragging
bindm = SUPER, mouse:272, movewindow
bindm = SUPER, mouse:273, resizewindow

# Close focused window with Super+W
bind = $mod, W, killactive,

# Force kitty to always tile
windowrulev2 = tile, class:^(kitty)$

# Force all Google Chrome windows to tile (including ChatGPT)
windowrulev2 = tile, class:^(Google-chrome)$

# Scroll faster in the terminal
windowrule = scrolltouchpad 1.5, class:Kitty

exec-once = hyprpaper &
exec-once = waybar &
exec-once = walker --gapplication-service &

πŸ“¦ Step 4: Stow Your Configs

From inside your ~/dotfiles repo:

cd ~/dotfiles

stow hypr
stow waybar
stow swayosd
stow hyprpaper

This will symlink the configs into ~/.config/ as expected.

πŸŒ„ Step 5: Set Up Wallpaper (Optional)

In hyprpaper.conf:

preload = ~/backgrounds/arch-mountains.png
wallpaper = eDP-1,~/backgrounds/arch-mountains.png

Adjust eDP-1 to match your display (run hyprctl monitors in Hyprland).

πŸ” Step 6: Log In to Hyprland

  1. Log out of GNOME
  2. At the GDM screen, click the gear icon βš™οΈ and select Hyprland
  3. Log in!

🧼 Bonus: Environment Variables (Optional)

Add this to ~/.profile or manage in your dotfiles:

export XDG_CURRENT_DESKTOP=Hyprland
export XDG_SESSION_TYPE=wayland
export GDK_BACKEND=wayland,x11
export QT_QPA_PLATFORM=wayland;xcb

πŸ§ͺ Final Thoughts

With this setup:

  • GNOME is still available
  • Hyprland can be selected at login
  • Your entire config is cleanly stowed in ~/dotfiles I’ll keep iterating on my dotfiles repo if you want to follow along.

Happy Hyprlanding πŸš€