How Hyprland Configuration is Organized in Omarchy: A Layered Approach Explained
Omarchy organizes Hyprland configuration through a three-layer priority system: default bootstrap files → theme-specific overrides → user personal settings, with ~/.config/hypr/hyprland.lua always loading last. This architecture keeps customizations safe from upstream changes while allowing themes to inject their own window rules and keybindings.
The Omarchy desktop environment treats Hyprland as a composable Lua system rather than a static config file. Understanding this layered organization helps you know exactly where to place modifications without breaking the refresh mechanism or losing changes on updates.
The Base Layer: Default Configuration Files
Every Hyprland setup in Omarchy starts from config/hypr/hyprland.lua. This file serves as the canonical source that the omarchy-refresh-config command copies into your home directory.
# Regenerate the official Hyprland config at ~/.config/hypr/hyprland.lua
omarchy-refresh-config hypr/hyprland.lua
The default config immediately loads default/hypr/bootstrap.lua, which performs two critical tasks:
- Initializes Omarchy's Lua helper functions (the
otable for bindings, window rules, etc.) - Prepends theme discovery paths to
package.pathso themes can override core modules
This bootstrap mechanism is verified in the test suite at [test/shell.d/config-test.sh](https://github.com/basecamp/omarchy/blob/quattro/test/shell.d/config-test.sh#L186), ensuring the sequence remains stable across releases.
The Theme Layer: Template Rendering and Theme Files
Omarchy's theming system generates Hyprland configurations dynamically. The process involves two distinct mechanisms:
Template Generation
The file default/themed/hyprland.lua.tpl contains the blueprint for default Hyprland settings. During a refresh, this template renders into default/hypr/hyprland.lua with theme-specific values substituted.
Theme-Specific Overrides
Individual themes ship their own hyprland.lua files (for example, themes/kanagawa/hyprland.lua). Because the bootstrap prepends theme directories to package.path, a theme's module wins over the generic template when both define the same bindings or rules.
The priority works like this:
- Bootstrap establishes the Lua environment
- Default template provides base configuration
- Theme file replaces or extends specific settings
- User config executes last with final authority
The User Layer: Personal Configuration at ~/.config/hypr/hyprland.lua
After all system and theme files load, Omarchy requires your personal configuration. This file location is documented in [manual/31-dotfiles.md](https://github.com/basecamp/omarchy/blob/quattro/manual/31-dotfiles.md#L11) as the stable interface for customizations.
A minimal user config loads the Omarchy helpers then adds personal modifications:
-- ~/.config/hypr/hyprland.lua
require("default.hypr.omarchy") -- load core helpers and defaults
-- Add custom keybinding
o.bind("SUPER+Enter", "alacritty")
-- Override window rule from theme
o.window("special:my_scratchpad", { size = "80% 80%" })
You can also require theme modules explicitly if you want to combine multiple theme features:
-- ~/.config/hypr/hyprland.lua
require("default.hypr.omarchy")
require("themes.kanagawa") -- pull in Kanagawa color scheme and rules
Helper Modules Under default/hypr/
Omarchy ships a library of reusable Lua modules in the default/hypr/ directory. The main entry point default/hypr/omarchy.lua aggregates these helpers:
windows.lua— window rule constructionbindings.lua— keybinding definitionsmonitors.lua— display configuration utilities
These are optional but recommended—they provide type-safe wrappers around raw Hyprland directives and maintain compatibility with Omarchy's refresh system.
Refresh and Migration Safety
The omarchy-refresh-config CLI tool handles config regeneration. Migration scripts in the migrations/ directory ensure upgrades don't break existing setups. For example, [migrations/1781063758.sh](https://github.com/basecamp/omarchy/blob/quattro/migrations/1781063758.sh#L3) verifies the bootstrap line is present and strips legacy path modifications that would interfere with the current layering.
This means you can safely run:
omarchy-refresh-config hypr/hyprland.lua
Without losing your ~/.config/hypr/hyprland.lua personalizations—the command only regenerates the base file, and your user config loads afterward by design.
Summary
- Default layer:
config/hypr/hyprland.luacopied byomarchy-refresh-config, bootstraps viadefault/hypr/bootstrap.lua - Theme layer: Template at
default/themed/hyprland.lua.tplrenders defaults; individual themes inject overrides viapackage.pathpriority - User layer:
~/.config/hypr/hyprland.lualoads last with guaranteed final authority - Helper modules:
default/hypr/omarchy.luaand submodules provide type-safe configuration primitives - Safety mechanism: Refresh and migration scripts preserve the three-layer order across updates
Frequently Asked Questions
Where should I put my custom Hyprland keybindings in Omarchy?
Add them to ~/.config/hypr/hyprland.lua. This file is guaranteed to load after all default and theme configurations, so your bindings will override or extend earlier definitions. Never edit the file generated by omarchy-refresh-config directly—your changes would be lost on the next refresh.
What happens to my Hyprland config when I run omarchy-refresh-config?
The command regenerates the base config from config/hypr/hyprland.lua into your home directory. Your personal ~/.config/hypr/hyprland.lua remains untouched because it exists in a separate location and is merely required at the end of the generated file. Migration scripts automatically fix any bootstrap line issues.
Can I use multiple Omarchy themes with different Hyprland settings simultaneously?
Yes—your user config can require() theme modules explicitly. For example, require("themes.kanagawa") after loading default.hypr.omarchy pulls in that theme's window rules and bindings. Only one theme's generated template applies during refresh, but manual requires let you mix theme fragments.
What is the o object in Hyprland Lua configs?
It's Omarchy's helper table initialized by default/hypr/bootstrap.lua. The o object provides methods like o.bind() for keybindings and o.window() for window rules, offering validation and cleaner syntax than raw Hyprland configuration directives.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →