Hyprland VRR Configuration: Enabling Variable Refresh Rate Per-Monitor and Globally

TLDR: Hyprland enables Variable Refresh Rate through a monitor rule parser that reads vrr values in src/config/shared/monitor/Parser.cpp, applies them via CMonitorRuleManager::ensureVRR() in MonitorRuleManager.cpp, and falls back to the misc:vrr integer setting when no per-monitor rule exists.

Hyprland VRR configuration controls adaptive sync behavior across displays in the Hyprland Wayland compositor. The repository implements a tiered system where per-monitor rules override a global misc:vrr fallback, with runtime state tracked in each CMonitor instance. Understanding this pipeline is essential for eliminating screen tearing without sacrificing performance.

Parsing Hyprland VRR Configuration Rules

When a configuration line contains vrr = <int>, Hyprland routes the string to CMonitorRuleParser::parseVRR in src/config/shared/monitor/Parser.cpp. This method validates that the input is numeric, converts it with std::stoi, and stores the result in CMonitorRule::m_vrr.

The parser treats negative values as an explicit disable, assigning std::nullopt, while zero or positive values are stored as an active optional integer:

// src/config/shared/monitor/Parser.cpp
bool CMonitorRuleParser::parseVRR(const std::string& value) {
    if (!isNumber(value)) { m_error += "invalid vrr "; return false; }
    const auto VRR = std::stoi(value);
    m_rule.m_vrr = VRR < 0 ? std::nullopt : std::optional(VRR);
    return true;
}

(source: Parser.cpp L64‑L73)

Applying VRR Settings to Monitors

CMonitorRuleManager::ensureVRR and Global Fallback

After the monitor configuration loads, CMonitorRuleManager::ensureVRR() is invoked for each output. The implementation in src/config/shared/monitor/MonitorRuleManager.cpp first queries the global fallback from misc:vrr using CConfigValue<Config::INTEGER>("misc:vrr").

The effective VRR setting, USEVRR, prioritizes the monitor rule if present; otherwise it inherits the global value:

// src/config/shared/monitor/MonitorRuleManager.cpp (excerpt)
void CMonitorRuleManager::ensureVRR(PHLMONITOR pMonitor) {
    static auto PVRR = CConfigValue<Config::INTEGER>("misc:vrr");
    const auto USEVRR = m->m_activeMonitorRule.m_vrr.has_value()
        ? m->m_activeMonitorRule.m_vrr.value() : *PVRR;
    // … logic that enables/disables VRR based on USEVRR and fullscreen state …
}

(source: MonitorRuleManager.cpp L195‑L210)

Depending on USEVRR, the compositor either enables adaptive sync, forces it off, or decides dynamically based on fullscreen and window state.

Runtime VRR State Tracking

Each CMonitor instance maintains a boolean flag reflecting whether VRR is currently active. In src/output/Monitor.hpp, the member m_vrrActive is initialized to false and updated after ensureVRR() succeeds:

// src/output/Monitor.hpp
bool m_vrrActive = false;   // true when adaptive‑sync (VRR) is active

(source: Monitor.hpp L107)

Global VRR Fallback Behavior

The misc:vrr Config Values

The global default is defined in src/config/values/ConfigValues.cpp under the key misc:vrr. According to the Hyprland source code, this integer controls the default adaptive sync policy when no per-monitor rule overrides it:

  • 0 – VRR is never enabled.
  • 1 – VRR is enabled unless a window explicitly disables it with the no_vrr rule.
  • 2 – VRR is enabled only when a fullscreen window is present.
  • 3 – VRR is enabled for fullscreen windows and when the content type is a game or video.
// src/config/values/ConfigValues.cpp
MS<Int>("misc:vrr", "controls the VRR (Adaptive Sync) of your monitors", 0,

(source: ConfigValues.cpp L483‑L485)

Interaction with Fullscreen Windows and Window Rules

When a window specifies the no_vrr rule, ensureVRR() respects that restriction and may temporarily disable adaptive sync while that window is fullscreen. This logic is handled inside the fullscreen controller. You can force VRR off for specific applications with a window rule:

windowrule = no_vrr, class:Firefox

Practical Hyprland VRR Configuration Examples

Per-Monitor VRR Rules

To enable VRR on a single display, define the monitor rule with the vrr value. The following example sets a monitor and enables its adaptive sync:

monitor=HDMI-A-1,2560x1440,60,1  # last “1” enables VRR for this monitor

Global VRR Settings

Use the misc:vrr key to set compositor-wide behavior. For instance, disabling VRR entirely or limiting it to fullscreen contexts:

misc:vrr = 0
misc:vrr = 2

The first snippet disables VRR globally. The second enables it only when a fullscreen window is active.

Lua Configuration

For Lua-based setups, assign the rule table directly and set the global fallback:

-- Enable VRR for the primary monitor
monitorRule = {
    name = "eDP-1",
    vrr = 1,
}

-- Global fallback: VRR only when a fullscreen window is active
Config.misc.vrr = 2

Summary

  • Per-monitor parsing: CMonitorRuleParser::parseVRR in src/config/shared/monitor/Parser.cpp validates and stores the vrr integer as std::optional<int> in m_rule.m_vrr.
  • Rule application: CMonitorRuleManager::ensureVRR() in src/config/shared/monitor/MonitorRuleManager.cpp resolves the effective VRR value by checking the monitor rule first, then the global misc:vrr fallback.
  • State tracking: Each output stores its live adaptive sync status in CMonitor::m_vrrActive, defined in src/output/Monitor.hpp.
  • Global fallback values: misc:vrr accepts 0 through 3, controlling whether VRR is off, always on, fullscreen-only, or content-type aware.
  • Window-level overrides: The no_vrr window rule suppresses VRR for specific applications, even when fullscreen.

Frequently Asked Questions

How do I enable VRR for a specific monitor in Hyprland?

Define a per-monitor rule with the vrr field. As implemented in src/config/shared/monitor/Parser.cpp, parseVRR() converts a positive integer into an enabled rule stored in CMonitorRule::m_vrr, which ensureVRR() then applies to that output. For example, set monitor=HDMI-A-1,2560x1440,60,1 to target that display.

What does the misc:vrr setting control?

misc:vrr acts as the global fallback when no per-monitor rule exists. Defined in src/config/values/ConfigValues.cpp, it accepts values 0 through 3: 0 disables adaptive sync entirely, 1 enables it by default, 2 restricts it to fullscreen windows, and 3 includes game or video content types.

Can I disable VRR for individual windows?

Yes. The no_vrr window rule instructs the fullscreen controller to temporarily suspend adaptive sync for matching clients. CMonitorRuleManager::ensureVRR() checks this condition and can force VRR off while the restricted window is active.

Where is the active VRR state stored at runtime?

Each monitor object tracks its current adaptive sync status in the m_vrrActive boolean, declared in src/output/Monitor.hpp at line 107. Additional layout-wide queries are available through isVRRActiveOnAnyMonitor() in src/state/MonitorLayoutController.hpp.

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 →