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 o table for bindings, window rules, etc.)
  • Prepends theme discovery paths to package.path so 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:

  1. Bootstrap establishes the Lua environment
  2. Default template provides base configuration
  3. Theme file replaces or extends specific settings
  4. 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:

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.lua copied by omarchy-refresh-config, bootstraps via default/hypr/bootstrap.lua
  • Theme layer: Template at default/themed/hyprland.lua.tpl renders defaults; individual themes inject overrides via package.path priority
  • User layer: ~/.config/hypr/hyprland.lua loads last with guaranteed final authority
  • Helper modules: default/hypr/omarchy.lua and 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:

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 →