# How Hyprland Parses and Applies Workspace Rules: A Deep Dive into the Source Code

> Discover how Hyprland parses and applies workspace rules. Explore the source code to understand rule management and runtime application for dynamic workspace configurations.

- Repository: [Hypr Development/Hyprland](https://github.com/hyprwm/Hyprland)
- Tags: deep-dive
- Published: 2026-07-23

---

**Hyprland parses workspace rules during configuration loading, stores them as `CWorkspaceRule` objects in a global `WorkspaceRuleManager`, and applies them at runtime when workspaces are created to bind them to specific monitors or set persistent flags.**

Hyprland’s workspace rule system lets users bind workspaces to monitors, mark them as persistent, or configure special attributes directly from [`hyprland.conf`](https://github.com/hyprwm/Hyprland/blob/main/hyprland.conf). This guide examines the implementation in the `hyprwm/Hyprland` repository to explain exactly how raw configuration strings transform into enforced window management behavior.

## The Three-Stage Pipeline: From Config to Runtime

Workspace rule processing follows a distinct pipeline: parsing, storage, and application. Each stage is handled by specific components in the source tree.

### Stage 1: Parsing Configuration Lines

When Hyprland loads its configuration, the parser identifies lines beginning with the `workspace` keyword. In [`src/config/shared/workspace/WorkspaceRuleManager.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/config/shared/workspace/WorkspaceRuleManager.cpp), the parser instantiates a **CWorkspaceRule** object for every valid rule encountered.

Each `CWorkspaceRule` stores:
- `m_workspaceString`: The raw selector (e.g., `"3"` or `"chat"`)
- `m_workspaceId`: The resolved numeric ID
- `m_monitor`: The target monitor name (e.g., `"DP-1"`)
- `m_persistent`, `m_enabled`: Boolean flags for persistence and initial state

The parser normalizes workspace selectors, resolving named workspaces to IDs and handling special workspace prefixes (`special:`) by assigning IDs in the `SPECIAL_WORKSPACE_START` range defined in the headers.

### Stage 2: Storing Rules in WorkspaceRuleManager

All parsed `CWorkspaceRule` objects are maintained by the global **WorkspaceRuleManager**, accessible via `Config::workspaceRuleMgr()`. This singleton provides the primary API for rule retrieval:

- `getBoundMonitorForWS(const std::string& wsName)`: Returns the monitor name a workspace should occupy
- `getAllWorkspaceRules()`: Returns the complete vector for iteration

The manager persists these rules for the entire session, ensuring that configuration changes (hot-reloads) update the rule set atomically.

### Stage 3: Applying Rules During Workspace Creation

Rules are enforced when workspaces are instantiated, not merely when the config loads. In [`src/state/WorkspaceState.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/state/WorkspaceState.cpp), the `CWorkspaceStateTracker::createWorkspace()` method queries the rule manager before finalizing workspace placement:

```cpp
// Inside CWorkspaceStateTracker::createWorkspace(...)
if (const auto pMonitor = Config::workspaceRuleMgr()->getBoundMonitorForWS(NAME); pMonitor)
    // The workspace is bound to a monitor → assign it

```

If a monitor binding exists, the workspace is added to that monitor’s workspace list, and the monitor is marked in the internal `m_seenMonitorWorkspaceMap`. Persistent workspaces are tracked separately in the manager’s `persistentWorkspaceIDs` vector to prevent ID reuse across sessions.

## Core Data Structures and Source Files

Understanding the implementation requires familiarity with these key files:

| File | Purpose |
|------|---------|
| [`src/config/shared/workspace/WorkspaceRule.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/config/shared/workspace/WorkspaceRule.hpp) | Defines the `CWorkspaceRule` class with member variables like `m_workspaceId` and `m_monitor` |
| [`src/config/shared/workspace/WorkspaceRuleManager.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/config/shared/workspace/WorkspaceRuleManager.hpp) | Declares the `WorkspaceRuleManager` singleton API |
| [`src/config/shared/workspace/WorkspaceRuleManager.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/config/shared/workspace/WorkspaceRuleManager.cpp) | Implements parsing logic and rule storage |
| [`src/state/WorkspaceState.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/state/WorkspaceState.cpp) | Contains `CWorkspaceStateTracker` where rules are applied during workspace creation |
| [`src/state/WorkspaceQueryCore.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/state/WorkspaceQueryCore.hpp) | Provides utilities for locating workspaces by ID or name during rule processing |

## Workspace Rule Syntax and Normalization

The configuration parser supports several rule variants:

```conf

# Bind workspace 1 to DisplayPort-1

workspace = 1 monitor:DP-1

# Create a persistent named workspace on HDMI-A-1

workspace = code persistent:true monitor:HDMI-A-1

# Define a disabled special workspace

workspace = special:something enabled:false

```

When parsing, Hyprland distinguishes between:
- **Numeric selectors**: Resolved directly to `m_workspaceId`
- **Named selectors**: Mapped to internal IDs, with persistence tracked separately
- **Special selectors**: Prefixed with `special:`, assigned IDs from `SPECIAL_WORKSPACE_START` upward

## Practical Configuration Examples

To pin workspace 3 to a specific monitor and keep it alive through restarts:

```conf
workspace = 3 monitor:HDMI-A-1 persistent:true

```

To create a named workspace for chat applications:

```conf
workspace = chat monitor:DP-2 persistent:true

```

## Querying Rules Programmatically

Plugin developers can access workspace rules through the public API:

```cpp
#include <config/shared/workspace/WorkspaceRuleManager.hpp>

auto* ruleMgr = Config::workspaceRuleMgr();
if (auto monitor = ruleMgr->getBoundMonitorForWS("3")) {
    Hyprland::Log::info("Workspace 3 is bound to monitor {}", *monitor);
}

```

This allows external tools and plugins to respect user-defined workspace constraints when manipulating window state.

## Summary

- **Parsing**: Configuration lines starting with `workspace` are parsed into `CWorkspaceRule` objects in [`WorkspaceRuleManager.cpp`](https://github.com/hyprwm/Hyprland/blob/main/WorkspaceRuleManager.cpp), storing selectors, monitor bindings, and flags.
- **Storage**: Rules are maintained in the global `WorkspaceRuleManager` singleton, providing lookup methods like `getBoundMonitorForWS()`.
- **Application**: During workspace creation in [`WorkspaceState.cpp`](https://github.com/hyprwm/Hyprland/blob/main/WorkspaceState.cpp), `CWorkspaceStateTracker` queries the manager to enforce monitor bindings and persistence.
- **Special handling**: Named and special workspaces are normalized to numeric IDs, with persistent workspaces tracked separately to survive configuration reloads.

## Frequently Asked Questions

### What is the difference between numeric and named workspace rules in Hyprland?

Numeric rules (e.g., `workspace = 1`) reference workspaces by their ID directly, while named rules (e.g., `workspace = chat`) create a mapping between a string name and an internal ID. Both store the resolved ID in `m_workspaceId`, but named workspaces require additional lookup resolution during parsing. Special workspaces use the `special:` prefix and receive IDs starting from `SPECIAL_WORKSPACE_START`.

### How does Hyprland handle persistent workspaces internally?

Persistent workspaces are flagged with `m_persistent = true` in their `CWorkspaceRule` object. The `WorkspaceRuleManager` stores these IDs in a dedicated `persistentWorkspaceIDs` vector, ensuring Hyprland does not reuse these IDs for dynamic workspaces and that they survive configuration reloads and session restoration.

### Where are workspace rules applied when a new workspace is created?

Rules are applied in [`src/state/WorkspaceState.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/state/WorkspaceState.cpp) within the `CWorkspaceStateTracker::createWorkspace()` method. This function queries `Config::workspaceRuleMgr()->getBoundMonitorForWS()` to determine the target monitor and checks persistence flags before finalizing the workspace's initial state and monitor assignment.

### Can plugins access workspace rule information at runtime?

Yes. Plugins can include [`config/shared/workspace/WorkspaceRuleManager.hpp`](https://github.com/hyprwm/Hyprland/blob/main/config/shared/workspace/WorkspaceRuleManager.hpp) and call `Config::workspaceRuleMgr()` to access the singleton instance. The `getBoundMonitorForWS()` method allows reading monitor bindings, while `getAllWorkspaceRules()` provides iteration over the complete rule set for custom workspace management logic.