Agent Skill
2/7/2026

hyprland

Hyprland Skill

O
olafkfreund
10GitHub Stars
2Views
npx skills add olafkfreund/nixos_config

SKILL.md

Namehyprland
DescriptionHyprland Skill

name: hyprland version: 1.0 description: Hyprland Skill

Hyprland Skill

A specialized skill for configuring and customizing Hyprland window manager in NixOS using Home Manager, providing expert guidance on Wayland compositor setup, essential packages, plugins, and declarative configuration.

Skill Overview

Purpose: Provide comprehensive support for Hyprland configuration, customization, and ecosystem integration in NixOS.

Invoke When:

  • Setting up Hyprland window manager
  • Configuring Hyprland via Home Manager
  • Installing Hyprland plugins and extensions
  • Setting up Waybar, rofi-wayland, or other companions
  • Troubleshooting Hyprland issues
  • Migrating from X11 window managers to Hyprland
  • Customizing Hyprland keybindings and behavior
  • Optimizing Hyprland performance

Core Capabilities

1. Installation and Configuration

Two-Module Approach (Recommended)

The best practice is using both NixOS and Home Manager modules for optimal integration.

NixOS Module (configuration.nix):

{ config, pkgs, ... }:
{
  # Enable Hyprland system-wide
  programs.hyprland = {
    enable = true;

    # Optional: Use nightly builds
    # package = inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system}.hyprland;

    # Enable XWayland support (for X11 apps)
    xwayland.enable = true;

    # UWSM support (New in 2025 - Recommended)
    withUWSM = true;  # Universal Wayland Session Manager
  };

  # Portal configuration for screen sharing
  xdg.portal = {
    enable = true;
    extraPortals = with pkgs; [
      xdg-desktop-portal-gtk
    ];
  };

  # Required for some applications
  environment.sessionVariables = {
    # Hint electron apps to use Wayland
    NIXOS_OZONE_WL = "1";
  };
}

Home Manager Module (home.nix):

{ config, pkgs, lib, ... }:
{
  wayland.windowManager.hyprland = {
    enable = true;

    # Use system package (recommended)
    package = null;  # Uses NixOS module package
    portalPackage = null;  # Uses NixOS module portal package

    # Enable systemd integration
    systemd = {
      enable = true;
      variables = ["--all"];
    };

    # XWayland support
    xwayland.enable = true;

    # Declarative settings (recommended)
    settings = {
      # See section 2 for detailed settings
    };

    # Or use extraConfig for raw config
    # extraConfig = ''
    #   # Your hyprland.conf here
    # '';
  };
}

Flake-based Setup:

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    # Optional: Use Hyprland flake for latest features
    hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1";
  };

  outputs = { nixpkgs, home-manager, hyprland, ... }:
  {
    nixosConfigurations.hostname = nixpkgs.lib.nixosSystem {
      modules = [
        # Import Hyprland NixOS module
        hyprland.nixosModules.default

        # Your configuration
        {
          programs.hyprland.enable = true;
        }

        # Home Manager with Hyprland
        home-manager.nixosModules.home-manager
        {
          home-manager.users.username = {
            imports = [ hyprland.homeManagerModules.default ];

            wayland.windowManager.hyprland = {
              enable = true;
              # Configuration
            };
          };
        }
      ];
    };
  };
}

2. Declarative Configuration (Settings)

Complete Settings Example

wayland.windowManager.hyprland.settings = {
  # Monitors
  monitor = [
    "DP-1,3840x2160@144,0x0,1"
    "HDMI-A-1,1920x1080@60,3840x0,1"
    ",preferred,auto,1"  # Fallback for unknown monitors
  ];

  # Workspace assignment
  workspace = [
    "1, monitor:DP-1, default:true"
    "2, monitor:DP-1"
    "9, monitor:HDMI-A-1"
  ];

  # Environment variables
  env = [
    "XCURSOR_SIZE,24"
    "HYPRCURSOR_SIZE,24"
    "QT_QPA_PLATFORM,wayland"
    "SDL_VIDEODRIVER,wayland"
    "GDK_BACKEND,wayland,x11"
  ];

  # Autostart
  exec-once = [
    "waybar"
    "hyprpaper"
    "dunst"
    "nm-applet"
    "blueman-applet"
    "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"
  ];

  # General settings
  general = {
    gaps_in = 5;
    gaps_out = 10;
    border_size = 2;

    # Colors
    "col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg";
    "col.inactive_border" = "rgba(595959aa)";

    layout = "dwindle";
    resize_on_border = true;
  };

  # Decorations
  decoration = {
    rounding = 10;

    blur = {
      enabled = true;
      size = 3;
      passes = 1;
      new_optimizations = true;
    };

    drop_shadow = true;
    shadow_range = 4;
    shadow_render_power = 3;
    "col.shadow" = "rgba(1a1a1aee)";
  };

  # Animations
  animations = {
    enabled = true;

    bezier = [
      "myBezier, 0.05, 0.9, 0.1, 1.05"
      "linear, 0, 0, 1, 1"
      "easeInOutCubic, 0.65, 0, 0.35, 1"
    ];

    animation = [
      "windows, 1, 7, myBezier"
      "windowsOut, 1, 7, default, popin 80%"
      "border, 1, 10, default"
      "fade, 1, 7, default"
      "workspaces, 1, 6, default"
      "specialWorkspace, 1, 6, default, slidevert"
    ];
  };

  # Input settings
  input = {
    kb_layout = "us";
    kb_variant = "";
    kb_options = "caps:escape";  # Caps as Escape

    follow_mouse = 1;

    touchpad = {
      natural_scroll = true;
      disable_while_typing = true;
      tap-to-click = true;
    };

    sensitivity = 0;  # -1.0 to 1.0, 0 = no modification
  };

  # Gestures
  gestures = {
    workspace_swipe = true;
    workspace_swipe_fingers = 3;
    workspace_swipe_distance = 300;
    workspace_swipe_cancel_ratio = 0.5;
  };

  # Layout settings
  dwindle = {
    pseudotile = true;
    preserve_split = true;
    special_scale_factor = 0.8;
  };

  master = {
    new_status = "master";
    new_on_top = false;
    mfact = 0.5;
  };

  # Miscellaneous
  misc = {
    disable_hyprland_logo = true;
    disable_splash_rendering = true;
    mouse_move_enables_dpms = true;
    key_press_enables_dpms = true;
    vrr = 1;  # Variable refresh rate
    enable_swallow = true;
    swallow_regex = "^(Alacritty|kitty|foot)$";
  };

  # Window rules
  windowrule = [
    "float, ^(pavucontrol)$"
    "float, ^(nm-connection-editor)$"
    "float, title:^(Picture-in-Picture)$"
    "pin, title:^(Picture-in-Picture)$"
    "opacity 0.9, ^(Alacritty)$"
  ];

  windowrulev2 = [
    "opacity 0.8 0.8, class:^(Code)$"
    "float, class:^(firefox)$, title:^(Picture-in-Picture)$"
    "pin, class:^(firefox)$, title:^(Picture-in-Picture)$"
    "workspace 2, class:^(firefox)$"
    "workspace 3, class:^(Code)$"
  ];

  # Layer rules
  layerrule = [
    "blur, waybar"
    "ignorezero, waybar"
    "blur, notifications"
    "ignorezero, notifications"
  ];
};

3. Keybindings Configuration

Essential Keybindings

wayland.windowManager.hyprland.settings = {
  # Modifier key
  "$mod" = "SUPER";

  # Keybindings
  bind = [
    # Application launchers
    "$mod, Return, exec, alacritty"
    "$mod, Q, killactive"
    "$mod, M, exit"
    "$mod, E, exec, thunar"
    "$mod, V, togglefloating"
    "$mod, R, exec, rofi -show drun"
    "$mod, P, pseudo"  # dwindle
    "$mod, J, togglesplit"  # dwindle

    # Move focus
    "$mod, left, movefocus, l"
    "$mod, right, movefocus, r"
    "$mod, up, movefocus, u"
    "$mod, down, movefocus, d"

    # Vim-style focus
    "$mod, h, movefocus, l"
    "$mod, l, movefocus, r"
    "$mod, k, movefocus, u"
    "$mod, j, movefocus, d"

    # Switch workspaces
    "$mod, 1, workspace, 1"
    "$mod, 2, workspace, 2"
    "$mod, 3, workspace, 3"
    "$mod, 4, workspace, 4"
    "$mod, 5, workspace, 5"
    "$mod, 6, workspace, 6"
    "$mod, 7, workspace, 7"
    "$mod, 8, workspace, 8"
    "$mod, 9, workspace, 9"
    "$mod, 0, workspace, 10"

    # Move window to workspace
    "$mod SHIFT, 1, movetoworkspace, 1"
    "$mod SHIFT, 2, movetoworkspace, 2"
    "$mod SHIFT, 3, movetoworkspace, 3"
    "$mod SHIFT, 4, movetoworkspace, 4"
    "$mod SHIFT, 5, movetoworkspace, 5"
    "$mod SHIFT, 6, movetoworkspace, 6"
    "$mod SHIFT, 7, movetoworkspace, 7"
    "$mod SHIFT, 8, movetoworkspace, 8"
    "$mod SHIFT, 9, movetoworkspace, 9"
    "$mod SHIFT, 0, movetoworkspace, 10"

    # Special workspaces (scratchpad)
    "$mod, S, togglespecialworkspace, magic"
    "$mod SHIFT, S, movetoworkspace, special:magic"

    # Scroll through workspaces
    "$mod, mouse_down, workspace, e+1"
    "$mod, mouse_up, workspace, e-1"

    # Fullscreen
    "$mod, F, fullscreen, 0"
    "$mod SHIFT, F, fullscreen, 1"  # Maximize

    # Screenshot
    ", Print, exec, grimblast copy area"
    "$mod, Print, exec, grimblast copy screen"

    # Media keys
    ", XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"
    ", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
    ", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
    ", XF86AudioPlay, exec, playerctl play-pause"
    ", XF86AudioPause, exec, playerctl pause"
    ", XF86AudioNext, exec, playerctl next"
    ", XF86AudioPrev, exec, playerctl previous"

    # Brightness
    ", XF86MonBrightnessUp, exec, brightnessctl set 10%+"
    ", XF86MonBrightnessDown, exec, brightnessctl set 10%-"

    # Lock screen
    "$mod, L, exec, hyprlock"
  ];

  # Mouse bindings
  bindm = [
    "$mod, mouse:272, movewindow"
    "$mod, mouse:273, resizewindow"
  ];

  # Repeating binds
  binde = [
    # Resize windows
    "$mod CTRL, left, resizeactive, -10 0"
    "$mod CTRL, right, resizeactive, 10 0"
    "$mod CTRL, up, resizeactive, 0 -10"
    "$mod CTRL, down, resizeactive, 0 10"

    # Vim-style resize
    "$mod CTRL, h, resizeactive, -10 0"
    "$mod CTRL, l, resizeactive, 10 0"
    "$mod CTRL, k, resizeactive, 0 -10"
    "$mod CTRL, j, resizeactive, 0 10"
  ];

  # Move window binds
  bind = [
    "$mod SHIFT, left, movewindow, l"
    "$mod SHIFT, right, movewindow, r"
    "$mod SHIFT, up, movewindow, u"
    "$mod SHIFT, down, movewindow, d"

    # Vim-style move
    "$mod SHIFT, h, movewindow, l"
    "$mod SHIFT, l, movewindow, r"
    "$mod SHIFT, k, movewindow, u"
    "$mod SHIFT, j, movewindow, d"
  ];
};

4. Essential Packages

Complete Package Set

{ config, pkgs, ... }:
{
  home.packages = with pkgs; [
    # Hyprland ecosystem
    hyprpaper         # Wallpaper daemon
    hypridle          # Idle daemon
    hyprlock          # Screen lock
    hyprpicker        # Color picker
    hyprcursor        # Cursor manager

    # Status bar and panels
    waybar            # Status bar

    # Application launcher
    rofi-wayland      # App launcher

    # Notifications
    dunst             # Notification daemon
    mako              # Alternative notification daemon

    # Screenshot tools
    grim              # Screenshot
    slurp             # Select screen region
    grimblast         # Grim wrapper with clipboard
    swappy            # Screenshot editor

    # Clipboard management
    wl-clipboard      # CLI clipboard tools
    cliphist          # Clipboard history

    # Screen recording
    wf-recorder       # Screen recorder

    # Color temperature
    wlsunset          # Redshift for Wayland
    gammastep         # Alternative to wlsunset

    # File manager
    thunar            # GTK file manager
    # Or alternatives:
    # pcmanfm
    # dolphin
    # nautilus

    # Terminal emulators
    alacritty         # GPU-accelerated terminal
    kitty             # Alternative terminal
    foot              # Lightweight terminal

    # System utilities
    brightnessctl     # Screen brightness
    playerctl         # Media control
    pavucontrol       # Audio control (GUI)
    pamixer           # Audio control (CLI)

    # Network management
    networkmanagerapplet  # Network manager applet

    # Bluetooth
    blueman           # Bluetooth manager

    # Authentication agent
    polkit_gnome      # Polkit authentication

    # Display management
    wlr-randr         # Display configuration
    kanshi            # Display hotplug daemon

    # Logout menu
    wlogout           # Logout/shutdown menu

    # Wayland utilities
    wtype             # xdotool for Wayland
    wev               # Wayland event viewer
    wayvnc            # VNC server for wlroots

    # Eye candy
    swww              # Animated wallpapers

    # Performance
    wlroots           # Wayland compositor library
  ];
}

5. Waybar Configuration

Complete Waybar Setup

programs.waybar = {
  enable = true;
  systemd.enable = true;

  settings = {
    mainBar = {
      layer = "top";
      position = "top";
      height = 34;
      spacing = 4;

      modules-left = [
        "hyprland/workspaces"
        "hyprland/submap"
        "hyprland/window"
      ];

      modules-center = [
        "clock"
      ];

      modules-right = [
        "idle_inhibitor"
        "pulseaudio"
        "network"
        "cpu"
        "memory"
        "temperature"
        "backlight"
        "battery"
        "tray"
      ];

      # Module configurations
      "hyprland/workspaces" = {
        disable-scroll = true;
        all-outputs = true;
        format = "{icon}";
        format-icons = {
          "1" = "";
          "2" = "";
          "3" = "";
          "4" = "";
          "5" = "";
          urgent = "";
          focused = "";
          default = "";
        };
      };

      "hyprland/window" = {
        max-length = 50;
        separate-outputs = true;
      };

      "hyprland/submap" = {
        format = "✌️ {}";
        max-length = 8;
        tooltip = false;
      };

      clock = {
        timezone = "America/New_York";
        tooltip-format = "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>";
        format = "{:%H:%M}";
        format-alt = "{:%Y-%m-%d}";
      };

      cpu = {
        format = " {usage}%";
        tooltip = false;
      };

      memory = {
        format = " {}%";
      };

      temperature = {
        critical-threshold = 80;
        format = "{icon} {temperatureC}°C";
        format-icons = ["" "" ""];
      };

      backlight = {
        format = "{icon} {percent}%";
        format-icons = ["" "" "" "" "" "" "" ""];
      };

      battery = {
        states = {
          warning = 30;
          critical = 15;
        };
        format = "{icon} {capacity}%";
        format-charging = " {capacity}%";
        format-plugged = " {capacity}%";
        format-alt = "{icon} {time}";
        format-icons = ["" "" "" "" ""];
      };

      network = {
        format-wifi = " {essid}";
        format-ethernet = " {ipaddr}";
        format-linked = " {ifname} (No IP)";
        format-disconnected = "⚠ Disconnected";
        tooltip-format = "{ifname} via {gwaddr} ";
      };

      pulseaudio = {
        format = "{icon} {volume}%";
        format-bluetooth = "{icon} {volume}%";
        format-muted = "";
        format-icons = {
          headphone = "";
          hands-free = "";
          headset = "";
          phone = "";
          portable = "";
          car = "";
          default = ["" "" ""];
        };
        on-click = "pavucontrol";
      };

      idle_inhibitor = {
        format = "{icon}";
        format-icons = {
          activated = "";
          deactivated = "";
        };
      };

      tray = {
        spacing = 10;
      };
    };
  };

  style = ''
    * {
      border: none;
      border-radius: 0;
      font-family: "JetBrainsMono Nerd Font";
      font-size: 13px;
      min-height: 0;
    }

    window#waybar {
      background: rgba(30, 30, 46, 0.9);
      color: #cdd6f4;
    }

    #workspaces button {
      padding: 0 5px;
      color: #cdd6f4;
      background: transparent;
    }

    #workspaces button.active {
      color: #89b4fa;
    }

    #workspaces button.urgent {
      color: #f38ba8;
    }

    #workspaces button:hover {
      background: rgba(205, 214, 244, 0.1);
    }

    #clock,
    #battery,
    #cpu,
    #memory,
    #temperature,
    #backlight,
    #network,
    #pulseaudio,
    #tray,
    #idle_inhibitor {
      padding: 0 10px;
      margin: 0 5px;
    }

    #battery.charging {
      color: #a6e3a1;
    }

    #battery.warning:not(.charging) {
      color: #f9e2af;
    }

    #battery.critical:not(.charging) {
      color: #f38ba8;
    }
  '';
};

6. Rofi Configuration

Rofi-Wayland Setup

programs.rofi = {
  enable = true;
  package = pkgs.rofi-wayland;

  terminal = "${pkgs.alacritty}/bin/alacritty";

  theme = "Arc-Dark";

  extraConfig = {
    modi = "drun,run,window";
    show-icons = true;
    icon-theme = "Papirus";
    display-drun = " Apps";
    display-run = " Run";
    display-window = " Windows";
    drun-display-format = "{name}";
    window-format = "{w} · {c} · {t}";
    font = "JetBrainsMono Nerd Font 10";
  };
};

# Custom rofi theme
xdg.configFile."rofi/themes/custom.rasi".text = ''
  * {
    bg: #1e1e2e;
    bg-alt: #313244;
    fg: #cdd6f4;
    fg-alt: #6c7086;

    background-color: @bg;
    border: 0;
    margin: 0;
    padding: 0;
    spacing: 0;
  }

  window {
    width: 30%;
    border: 2px;
    border-color: #89b4fa;
    border-radius: 10px;
  }

  element {
    padding: 8 12;
    text-color: @fg-alt;
  }

  element selected {
    text-color: @fg;
    background-color: @bg-alt;
  }

  element-text {
    background-color: inherit;
    text-color: inherit;
  }

  element-icon {
    size: 1.2em;
  }

  entry {
    padding: 12;
    text-color: @fg;
  }

  inputbar {
    children: [prompt, entry];
    background-color: @bg-alt;
  }

  listview {
    columns: 1;
    lines: 8;
  }

  mainbox {
    children: [inputbar, listview];
  }

  prompt {
    enabled: true;
    padding: 12 0 0 12;
    text-color: @fg;
  }
'';

7. Additional Components

Hyprpaper (Wallpaper)

services.hyprpaper = {
  enable = true;

  settings = {
    ipc = "on";
    splash = false;

    preload = [
      "~/Pictures/Wallpapers/mountain.jpg"
      "~/Pictures/Wallpapers/city.png"
    ];

    wallpaper = [
      "DP-1,~/Pictures/Wallpapers/mountain.jpg"
      "HDMI-A-1,~/Pictures/Wallpapers/city.png"
      ",~/Pictures/Wallpapers/mountain.jpg"  # Fallback
    ];
  };
};

Hypridle (Idle Management)

services.hypridle = {
  enable = true;

  settings = {
    general = {
      lock_cmd = "pidof hyprlock || hyprlock";
      before_sleep_cmd = "loginctl lock-session";
      after_sleep_cmd = "hyprctl dispatch dpms on";
    };

    listener = [
      {
        timeout = 150;  # 2.5 minutes
        on-timeout = "brightnessctl -s set 10";
        on-resume = "brightnessctl -r";
      }
      {
        timeout = 300;  # 5 minutes
        on-timeout = "loginctl lock-session";
      }
      {
        timeout = 330;  # 5.5 minutes
        on-timeout = "hyprctl dispatch dpms off";
        on-resume = "hyprctl dispatch dpms on";
      }
      {
        timeout = 1800;  # 30 minutes
        on-timeout = "systemctl suspend";
      }
    ];
  };
};

Hyprlock (Screen Lock)

programs.hyprlock = {
  enable = true;

  settings = {
    general = {
      disable_loading_bar = true;
      grace = 0;
      hide_cursor = true;
      no_fade_in = false;
    };

    background = [
      {
        path = "screenshot";
        blur_passes = 3;
        blur_size = 8;
      }
    ];

    input-field = [
      {
        size = "200, 50";
        position = "0, -80";
        monitor = "";
        dots_center = true;
        fade_on_empty = false;
        font_color = "rgb(202, 211, 245)";
        inner_color = "rgb(91, 96, 120)";
        outer_color = "rgb(24, 25, 38)";
        outline_thickness = 5;
        placeholder_text = ''<span foreground="##cad3f5">Password...</span>'';
        shadow_passes = 2;
      }
    ];
  };
};

Dunst (Notifications)

services.dunst = {
  enable = true;

  settings = {
    global = {
      width = 300;
      height = 300;
      offset = "30x50";
      origin = "top-right";
      transparency = 10;
      frame_color = "#89b4fa";
      font = "JetBrainsMono Nerd Font 10";
      format = "<b>%s</b>\n%b";
      alignment = "left";
      word_wrap = true;
      show_age_threshold = 60;
      idle_threshold = 120;
      icon_position = "left";
      max_icon_size = 48;
      corner_radius = 10;
    };

    urgency_low = {
      background = "#1e1e2e";
      foreground = "#cdd6f4";
      timeout = 5;
    };

    urgency_normal = {
      background = "#1e1e2e";
      foreground = "#cdd6f4";
      timeout = 10;
    };

    urgency_critical = {
      background = "#1e1e2e";
      foreground = "#f38ba8";
      frame_color = "#f38ba8";
      timeout = 0;
    };
  };
};

8. Plugins (Hyprland-Plugins)

Plugin Installation (NixOS)

{ inputs, pkgs, ... }:
{
  wayland.windowManager.hyprland = {
    enable = true;

    # Plugins (requires Hyprland flake)
    plugins = [
      inputs.hyprland-plugins.packages.${pkgs.stdenv.hostPlatform.system}.borders-plus-plus
      inputs.hyprland-plugins.packages.${pkgs.stdenv.hostPlatform.system}.hyprbars
      inputs.hyprland-plugins.packages.${pkgs.stdenv.hostPlatform.system}.hyprexpo
      inputs.hyprland-plugins.packages.${pkgs.stdenv.hostPlatform.system}.hyprtrails
      inputs.hyprland-plugins.packages.${pkgs.stdenv.hostPlatform.system}.hyprwinwrap
    ];
  };
}

Note: hyprpm is not supported on NixOS. Use the home-manager module for plugins.

Available Plugins

  • borders-plus-plus: Enhanced border customization
  • hyprbars: Window title bars for floating windows
  • hyprexpo: Workspace overview (Exposé-like)
  • hyprtrails: Mouse trail effects
  • hyprwinwrap: Xwinwrap equivalent for Hyprland

Plugin Configuration Example (hyprbars)

wayland.windowManager.hyprland.settings = {
  "plugin:hyprbars" = {
    bar_height = 20;
    bar_color = "rgb(1e1e2e)";
    "col.text" = "rgb(cdd6f4)";
    bar_text_font = "JetBrainsMono Nerd Font";
    bar_text_size = 10;
    bar_button_padding = 5;
    bar_padding = 10;
    bar_precedence_over_border = true;
  };
};

9. Per-Device Configuration

Multi-Monitor Setup

{ lib, ... }:
let
  # Detect hostname
  hostname = lib.fileContents /etc/hostname;

  # Monitor configurations per host
  monitorConfigs = {
    desktop = [
      "DP-1,3840x2160@144,0x0,1"
      "HDMI-A-1,1920x1080@60,3840x0,1"
    ];

    laptop = [
      "eDP-1,1920x1080@60,0x0,1"
    ];
  };

  # Get current config
  currentMonitors = monitorConfigs.${hostname} or monitorConfigs.laptop;
in
{
  wayland.windowManager.hyprland.settings = {
    monitor = currentMonitors;

    # Laptop-specific: disable built-in when lid closed
    bindl = lib.optionals (hostname == "laptop") [
      ",switch:on:Lid Switch,exec,hyprctl keyword monitor 'eDP-1,disable'"
      ",switch:off:Lid Switch,exec,hyprctl keyword monitor 'eDP-1,1920x1080@60,0x0,1'"
    ];
  };
}

Performance Tuning (Per-Device)

wayland.windowManager.hyprland.settings = {
  # High-end system
  decoration.blur = lib.mkIf (hostname == "desktop") {
    enabled = true;
    size = 8;
    passes = 3;
  };

  # Low-end system
  decoration.blur = lib.mkIf (hostname == "laptop") {
    enabled = false;
  };

  animations.enabled = hostname != "low-end";
};

Common Patterns and Solutions

Pattern 1: Systemd User Services

Custom Service for Hyprland

systemd.user.services.hyprland-startup = {
  Unit = {
    Description = "Hyprland startup script";
    After = [ "graphical-session.target" ];
  };

  Service = {
    Type = "oneshot";
    ExecStart = toString (pkgs.writeShellScript "hyprland-startup" ''
      # Wait for Hyprland
      until hyprctl monitors > /dev/null 2>&1;
        sleep 1
      done

      # Your startup commands
      ${pkgs.networkmanagerapplet}/bin/nm-applet &
      ${pkgs.blueman}/bin/blueman-applet &
    '');
  };

  Install.WantedBy = [ "hyprland-session.target" ];
};

Pattern 2: Display Hotplug (Kanshi)

services.kanshi = {
  enable = true;

  settings = [
    {
      profile.name = "undocked";
      profile.outputs = [
        {
          criteria = "eDP-1";
          scale = 1.0;
          status = "enable";
        }
      ];
    }
    {
      profile.name = "docked";
      profile.outputs = [
        {
          criteria = "eDP-1";
          status = "disable";
        }
        {
          criteria = "DP-1";
          scale = 1.0;
          position = "0,0";
        }
      ];
    }
  ];
};

Pattern 3: Environment Variables (UWSM)

With UWSM enabled:

# In home.nix with programs.hyprland.withUWSM = true
xdg.configFile."uwsm/env".text = ''
  export QT_QPA_PLATFORM=wayland
  export SDL_VIDEODRIVER=wayland
  export MOZ_ENABLE_WAYLAND=1
'';

Pattern 4: Clipboard Management

# Clipboard history with cliphist
systemd.user.services.cliphist = {
  Unit = {
    Description = "Clipboard history";
    After = [ "graphical-session.target" ];
  };

  Service = {
    ExecStart = "${pkgs.wl-clipboard}/bin/wl-paste --watch ${pkgs.cliphist}/bin/cliphist store";
    Restart = "always";
  };

  Install.WantedBy = [ "hyprland-session.target" ];
};

# Rofi clipboard menu keybind
wayland.windowManager.hyprland.settings.bind = [
  "$mod, V, exec, cliphist list | rofi -dmenu | cliphist decode | wl-copy"
];

Troubleshooting Guide

Issue 1: Screen Sharing Not Working

Problem: Cannot share screen in applications

Solution:

# Ensure portals are configured
xdg.portal = {
  enable = true;
  config.common.default = "*";
  extraPortals = with pkgs; [
    xdg-desktop-portal-hyprland
    xdg-desktop-portal-gtk
  ];
};

# Environment variables
home.sessionVariables = {
  XDG_CURRENT_DESKTOP = "Hyprland";
  XDG_SESSION_TYPE = "wayland";
};

Issue 2: NVIDIA Graphics Issues

Problem: Flickering or crashes with NVIDIA

Solution:

# NixOS configuration
programs.hyprland = {
  enable = true;

  # NVIDIA-specific settings
  nvidiaPatches = true;
};

# Hyprland settings
wayland.windowManager.hyprland.settings = {
  env = [
    "LIBVA_DRIVER_NAME,nvidia"
    "XDG_SESSION_TYPE,wayland"
    "GBM_BACKEND,nvidia-drm"
    "__GLX_VENDOR_LIBRARY_NAME,nvidia"
    "WLR_NO_HARDWARE_CURSORS,1"
  ];

  cursor.no_hardware_cursors = true;
};

# Enable modesetting in NixOS
hardware.nvidia.modesetting.enable = true;

Issue 3: Applications Not Using Wayland

Problem: Apps default to X11

Solution:

home.sessionVariables = {
  # Force Wayland for compatible apps
  MOZ_ENABLE_WAYLAND = "1";  # Firefox
  QT_QPA_PLATFORM = "wayland";
  SDL_VIDEODRIVER = "wayland";
  CLUTTER_BACKEND = "wayland";

  # Electron apps
  NIXOS_OZONE_WL = "1";
};

Issue 4: High CPU Usage

Problem: Hyprland using too much CPU

Solution:

wayland.windowManager.hyprland.settings = {
  # Disable animations
  animations.enabled = false;

  # Reduce blur
  decoration.blur = {
    enabled = true;
    size = 3;
    passes = 1;
  };

  # Disable shadows
  decoration.drop_shadow = false;

  # Reduce VRR
  misc.vrr = 0;
};

Issue 5: Monitor Not Detected

Problem: External monitor not recognized

Solution:

# Check connected monitors
hyprctl monitors

# Manually set monitor
hyprctl keyword monitor "HDMI-A-1,1920x1080@60,0x0,1"

# Reload configuration
hyprctl reload

Permanent fix:

wayland.windowManager.hyprland.settings = {
  monitor = [
    # Explicit configurations
    "DP-1,3840x2160@144,0x0,1"
    "HDMI-A-1,1920x1080@60,3840x0,1"
    # Fallback for any unknown monitor
    ",preferred,auto,1"
  ];
};

Best Practices

DO ✅

  1. Use both NixOS and Home Manager modules

    # NixOS for system integration
    programs.hyprland.enable = true;
    
    # Home Manager for user config
    wayland.windowManager.hyprland.enable = true;
    
  2. Use declarative settings over extraConfig

    # ✅ Preferred
    settings = {
      general.gaps_in = 5;
    };
    
    # ❌ Avoid when possible
    extraConfig = ''
      general {
        gaps_in = 5
      }
    '';
    
  3. Enable systemd integration

    wayland.windowManager.hyprland.systemd.enable = true;
    
  4. Use UWSM for session management (2025+)

    programs.hyprland.withUWSM = true;
    
  5. Set package to null for version sync

    wayland.windowManager.hyprland = {
      package = null;  # Use NixOS module package
      portalPackage = null;
    };
    
  6. Organize configuration in modules

    imports = [
      ./hyprland/settings.nix
      ./hyprland/binds.nix
      ./hyprland/rules.nix
    ];
    
  7. Use monitor fallback for portability

    monitor = [
      "DP-1,preferred,auto,1"
      ",preferred,auto,1"  # Catch-all
    ];
    
  8. Enable XWayland for compatibility

    xwayland.enable = true;
    

DON'T ❌

  1. Don't mix package versions

    # ❌ Bad - version mismatch
    programs.hyprland.package = pkgs.hyprland;
    wayland.windowManager.hyprland.package = inputs.hyprland.packages.x86_64-linux.hyprland;
    
  2. Don't use hyprpm on NixOS

    # ❌ Not supported
    hyprpm add https://github.com/plugin/repo
    
  3. Don't hardcode monitor names everywhere

    # ❌ Not portable
    workspace = [ "1, monitor:DP-1" ];
    
    # ✅ Better
    workspace = [ "1, default:true" ];
    
  4. Don't skip portal configuration

    # ❌ Screen sharing won't work
    
    # ✅ Required
    xdg.portal.enable = true;
    
  5. Don't ignore NVIDIA requirements

    # ❌ Will have issues on NVIDIA
    
    # ✅ Configure properly
    cursor.no_hardware_cursors = true;
    env = [ "WLR_NO_HARDWARE_CURSORS,1" ];
    

Command Reference

Hyprctl Commands

# Monitor management
hyprctl monitors                    # List monitors
hyprctl keyword monitor "name,res"  # Set monitor
hyprctl dispatch dpms off          # Turn off displays
hyprctl dispatch dpms on           # Turn on displays

# Workspace management
hyprctl workspaces                 # List workspaces
hyprctl dispatch workspace 1       # Switch workspace
hyprctl dispatch movetoworkspace 2 # Move window

# Window management
hyprctl clients                    # List windows
hyprctl activewindow              # Get active window
hyprctl dispatch killactive       # Close window
hyprctl dispatch togglefloating   # Toggle floating

# Configuration
hyprctl reload                    # Reload config
hyprctl keyword general:gaps_in 5 # Set option

# Information
hyprctl version                   # Hyprland version
hyprctl devices                   # Input devices
hyprctl binds                     # List keybinds
hyprctl animations               # List animations

# Plugin management (not for NixOS)
# hyprpm commands don't work on NixOS

Debugging Commands

# View Hyprland logs
journalctl --user -u hyprland.service

# Debug mode
Hyprland --debug

# Check Wayland socket
echo $WAYLAND_DISPLAY

# Test input
wev  # Wayland event viewer

# Check portals
systemctl --user status xdg-desktop-portal-hyprland

Resources and Documentation

Official Documentation

Community Resources

Useful Utilities

Ready to configure Hyprland! Let me know what you need help with. 🚀

Skills Info
Original Name:hyprlandAuthor:olafkfreund