# How Themes Are Structured and Applied in Omarchy: A Complete Technical Guide

> Explore Omarchy's directory based theming structure featuring a colors.toml palette and runtime generation pipeline for desktop shell configuration and template rendering.

- Repository: [37signals/omarchy](https://github.com/basecamp/omarchy)
- Tags: deep-dive
- Published: 2026-08-18

---

**Omarchy's theming system uses a directory-based structure with a [`colors.toml`](https://github.com/basecamp/omarchy/blob/main/colors.toml) palette and a runtime generation pipeline that renders templates and applies configuration to the desktop shell.**

In Omarchy, the Basecamp-developed open-source desktop environment, themes are not monolithic packages but modular, composable configurations. This article explains exactly how theme files are organized, how the `omarchy-theme-set` command transforms static palettes into active system configuration, and how you can extend or override themes with your own customizations.

## Theme Directory Structure and Core Files

Omarchy themes follow a strict directory convention. The [`colors.toml`](https://github.com/basecamp/omarchy/blob/main/colors.toml) file is mandatory—everything else is optional.

### System and User Theme Locations

Themes ship in two locations:

1. **System themes**: `/usr/share/omarchy/themes/<name>/` (installed from the `themes/<name>/` source tree)
2. **User themes**: `~/.config/omarchy/themes/<name>/`

User themes overlay system themes, allowing you to override specific files without forking the entire theme.

### Required and Optional Theme Files

| File | Purpose |
|------|---------|
| [`colors.toml`](https://github.com/basecamp/omarchy/blob/main/colors.toml) | **Required**. Defines the complete color palette |
| [`shell.toml`](https://github.com/basecamp/omarchy/blob/main/shell.toml) | Optional hand-written shell configuration |
| [`hyprland.lua`](https://github.com/basecamp/omarchy/blob/main/hyprland.lua) | Optional Hyprland window manager overrides |
| `icons.theme` | Optional icon theme specification |
| `keyboard.rgb` | Optional keyboard RGB lighting profile |
| `preview.png` | Optional preview image for theme selectors |

As documented in [`docs/theming.md`](https://github.com/basecamp/omarchy/blob/main/docs/theming.md), hand-written files like [`shell.toml`](https://github.com/basecamp/omarchy/blob/main/shell.toml) or [`hyprland.lua`](https://github.com/basecamp/omarchy/blob/main/hyprland.lua) take precedence over generated defaults. This lets theme authors selectively customize behavior while still benefiting from template generation for standard components.

## The Theme Generation Pipeline

The `omarchy-theme-set <name>` command implements a four-stage pipeline for applying themes. Understanding this pipeline is essential for debugging theme issues or creating custom themes.

### Stage 1: Staging Area Creation

The command creates a clean directory at `~/.local/state/omarchy/current/next-theme`:

```bash
STAGE="$HOME/.local/state/omarchy/current/next-theme"
mkdir -p "$STAGE"

```

### Stage 2: File Population and Overlay

First-party files copy from the system location, then user customizations overlay on top:

```bash

# Copy base theme

cp -a "/usr/share/omarchy/themes/$THEME/." "$STAGE/"

# Overlay user customizations if present

[[ -d "$HOME/.config/omarchy/themes/$THEME" ]] && \
    cp -a "$HOME/.config/omarchy/themes/$THEME/." "$STAGE/"

```

This overlay pattern means a user theme only needs to contain files that differ from the system theme.

### Stage 3: Template Rendering

The `omarchy-theme-set-templates` command processes all `.tpl` files in `default/themed/`:

```bash

# Only runs if colors.toml exists in the staged theme

[[ -f "$STAGE/colors.toml" ]] && omarchy-theme-set-templates "$STAGE"

```

Template files like `shell.toml.tpl` and `hyprland.lua.tpl` receive values from [`colors.toml`](https://github.com/basecamp/omarchy/blob/main/colors.toml) and render to their non-`.tpl` counterparts. The source files remain in `default/themed/*.tpl` and are not modified.

### Stage 4: Atomic Activation and Hooks

The staged theme moves into place, metadata records the theme name, and post-theme actions execute:

```bash
CURRENT="$HOME/.local/state/omarchy/current/theme"

# Atomic replacement

mv "$STAGE" "$CURRENT"
echo "$THEME" >"$HOME/.local/state/omarchy/current/theme.name"

# Execute hooks and restart/retint commands

# (internal dispatch via omarchy-theme-set)

```

## Template Rendering and Precedence Rules

The template system in Omarchy prioritizes explicit configuration over generated defaults.

### How Templates Work

Templates in `default/themed/*.tpl` use the palette defined in [`colors.toml`](https://github.com/basecamp/omarchy/blob/main/colors.toml). For example, a template might reference `{{accent}}` or `{{background}}` and receive the corresponding hex values.

### Precedence Hierarchy

When multiple sources define the same configuration:

1. **Highest**: Hand-written files in the theme directory ([`shell.toml`](https://github.com/basecamp/omarchy/blob/main/shell.toml), [`hyprland.lua`](https://github.com/basecamp/omarchy/blob/main/hyprland.lua))
2. **Middle**: Generated files from template rendering
3. **Lowest**: Default values built into applications

This hierarchy, documented in [`docs/theming.md`](https://github.com/basecamp/omarchy/blob/main/docs/theming.md) lines 31-34, ensures that theme authors retain fine-grained control where needed while avoiding repetitive boilerplate.

## Gradient Support and Special Keys

Omarchy's theme system supports both solid colors and Hyprland-style gradients for specific keys.

The `hyprland_active_border` key demonstrates this flexibility. A theme may define:

```toml

# Solid color fallback

accent = "#7aa2f7"

# Or explicit gradient

hyprland_active_border = "rgba(7aa2f7ee) rgba(bb9af7ee) 45deg"

```

If `hyprland_active_border` is absent, the system automatically falls back to the `accent` color. This pattern, described in [`docs/theming.md`](https://github.com/basecamp/omarchy/blob/main/docs/theming.md) lines 137-153, allows themes to opt into advanced visual effects without requiring gradient definitions for every property.

## Hooks and Post-Theme Actions

After theme activation, Omarchy notifies dependent components through two mechanisms.

### User-Defined Hooks

Scripts matching `~/.config/omarchy/hooks/theme-set*` execute with the theme name as `$1`:

```bash
#!/bin/bash

# ~/.config/omarchy/hooks/theme-set-notify

theme_name="$1"
notify-send "Theme changed" "Now using: $theme_name"

```

### System Post-Theme Commands

The `bin/omarchy-theme-set` script maintains a `post_theme_commands` list that restarts or retints applications needing to observe color changes. This includes:

- Terminal emulators
- Status bars
- Background tools

The exact commands depend on the Omarchy version and installed components.

## Runtime State and Active Theme Location

The directory `~/.local/state/omarchy/current/` serves as the single source of truth for the running theme:

| Path | Contents |
|------|----------|
| `~/.local/state/omarchy/current/theme/` | Fully resolved theme files (generated + hand-written) |
| `~/.local/state/omarchy/current/theme.name` | Plain text name of active theme |
| `~/.local/state/omarchy/current/next-theme/` | Temporary staging area during theme switch |

As noted in [`docs/update-process.md`](https://github.com/basecamp/omarchy/blob/main/docs/update-process.md) lines 26-29, applications and shell components read from this runtime directory rather than directly from `/usr/share/omarchy/themes/` or `~/.config/omarchy/themes/`.

## Practical Commands for Theme Management

```bash

# List all available themes (built-in and user)

omarchy theme list

# Apply a theme by exact name

omarchy theme set "Tokyo Night"

# Preview color ramp without installing

omarchy dev theme-preview "Tokyo Night"

```

The `omarchy-theme-set` binary underlies these commands. Direct invocation is possible but requires valid theme name validation that the `omarchy` CLI wrapper provides.

## Key Implementation Files

| File | Role |
|------|------|
| [`docs/theming.md`](https://github.com/basecamp/omarchy/blob/main/docs/theming.md) | Authoritative theme format and pipeline documentation |
| `bin/omarchy-theme-set` | Entry point for theme validation, staging, rendering, activation, and hooks |
| [`install/user/theme.sh`](https://github.com/basecamp/omarchy/blob/main/install/user/theme.sh) | User-side helper creating symlinks for theme-aware applications |
| `default/themed/*.tpl` | Template files rendered with [`colors.toml`](https://github.com/basecamp/omarchy/blob/main/colors.toml) values |
| `themes/<name>/colors.toml` | System theme color palettes |

## Summary

- **Themes require [`colors.toml`](https://github.com/basecamp/omarchy/blob/main/colors.toml)** as the mandatory palette definition, with optional hand-written overrides for specific components.
- **The `omarchy-theme-set` pipeline** stages, overlays, renders templates, and atomically activates themes to `~/.local/state/omarchy/current/`.
- **User themes in `~/.config/omarchy/themes/`** overlay system themes without requiring full copies.
- **Hand-written files win over generated templates**, which win over application defaults.
- **Hooks and post-theme commands** notify the shell and applications of color changes after activation.

## Frequently Asked Questions

### What is the minimum required file for an Omarchy theme?

A valid Omarchy theme requires only [`colors.toml`](https://github.com/basecamp/omarchy/blob/main/colors.toml) containing the color palette. All other files—[`shell.toml`](https://github.com/basecamp/omarchy/blob/main/shell.toml), [`hyprland.lua`](https://github.com/basecamp/omarchy/blob/main/hyprland.lua), icons, and preview images—are optional. The `omarchy-theme-set` command will generate default configurations from templates using the palette values.

### How do I override a built-in theme without modifying system files?

Create a directory at `~/.config/omarchy/themes/<name>/` matching the system theme name, then place only the files you want to override. The overlay system in `bin/omarchy-theme-set` copies your files on top of the system theme during staging. Your changes persist across Omarchy updates.

### Why does my theme change not apply immediately to some applications?

Applications must explicitly observe the `~/.local/state/omarchy/current/` directory or respond to the post-theme hook mechanism. The `post_theme_commands` list in `bin/omarchy-theme-set` handles restarts for known applications; others may need custom hook scripts in `~/.config/omarchy/hooks/theme-set*`.

### Can I use gradients instead of solid colors for window borders?

Yes. Define `hyprland_active_border` as a Hyprland-style gradient string in [`colors.toml`](https://github.com/basecamp/omarchy/blob/main/colors.toml) (for example, `rgba(7aa2f7ee) rgba(bb9af7ee) 45deg`). If this key is absent, Omarchy automatically falls back to the `accent` color as a solid border.