Unofficial community reference. Not affiliated with 37signals or the Omacom Foundation. Download Omarchy only from omarchy.org.
omarchylinux.org Unofficial field manual

Multi-monitor layout not saved: scale and position reset on Omarchy 4

Your external monitor layout, scale and position do not survive a reload on Omarchy 4. Write explicit hl.monitor rules in monitors.lua, then reload.

Workaround available Applies to Omarchy 4.0.0 and later Last verified 2026-09-16 on 4.0.4
Short answer

Omarchy 4's Display panel and Super + / only persist scale into the catch-all rule in ~/.config/hypr/monitors.lua, and on a docked laptop a watcher polls every two seconds and re-applies the internal panel's scale from that file, with position "auto" unless a connector-name rule sets one. Write one literal hl.monitor line per output, keyed by connector name, with the scale and position you want, then run hyprctl reload and stop using the scale buttons.

On this page
  1. The fix
  2. Verify it worked
  3. Why it happens
  4. If that did not work
  5. Related

You arrange your screens, set a scale, and it looks right. Then you reload, dock, undock, or reboot, and the layout is back where it started. On Omarchy 4 this is usually not Hyprland losing your config. It is Omarchy writing over it.

The fix

Checked on 4.0.4. The same steps apply to 4.0.0 through 4.0.3. On 3.x the file is monitors.conf and only step 5 applies, see the Quattro config page.

  1. Get your real output names. Run hyprctl monitors all. Note the connector name (eDP-1, DP-2, HDMI-A-1), the mode you want, and the description string if you have two identical panels.

  2. Open the file. Use Setup > Monitors in the Omarchy menu, which runs omarchy-launch-config-editor "$HOME/.config/hypr/monitors.lua".

  3. Write one explicit rule per output, each on a single literal line, above the shipped catch-all. Keep the catch-all last so any screen you did not name still comes up:

    local omarchy_gdk_scale = 1
    local omarchy_monitor_scale = "auto"
    
    hl.env("GDK_SCALE", tostring(omarchy_gdk_scale))
    
    hl.monitor({ output = "DP-2", mode = "2560x1440@165", position = "0x0", scale = 1 })
    hl.monitor({ output = "HDMI-A-1", mode = "1920x1080@60", position = "auto-right", scale = 1 })
    hl.monitor({ output = "eDP-1", mode = "preferred", position = "auto-down", scale = 1.6 })
    
    hl.monitor({ output = "", mode = "preferred", position = "auto", scale = omarchy_monitor_scale })
  4. Prefer relative positions. Use auto-right, auto-left, auto-up or auto-down rather than pixel coordinates unless every screen is at scale 1. Absolute coordinates are computed against logical pixels, so a 1080p screen at scale 1.25 is only 864 logical pixels tall and a neighbour pinned at 0x1080 leaves a gap your cursor cannot cross. syskey8 worked the arithmetic out in discussion #8213.

  5. Set GDK_SCALE to the nearest whole number of your largest monitor scale. GTK only honours integers, and apps already running keep the old value until you restart them.

  6. Reload with hyprctl reload. Do not use hyprctl keyword monitor ... from a 3.x guide. Omarchy 4 loads Hyprland through Lua, and that call fails with keyword can't work with non-legacy parsers. Use eval.

  7. From now on, change scale by editing the rule, not with the Display panel buttons or Super + /. Those call omarchy-hyprland-monitor-scaling, which is the source of most of the resets described below.

Verify it worked

Read the live state back and compare it to what you wrote:

hyprctl monitors all -j | jq -r '.[] | "\(.name) \(.width)x\(.height) scale=\(.scale) at \(.x)x\(.y) transform=\(.transform)"'

Then wait ten seconds and run it again. A docked laptop is re-checked every two seconds, so a layout that is going to be overwritten will change within that window. Check hyprctl configerrors for a silent parse failure, unplug and replug the external screen, and reboot once. If a scale keeps moving on its own, ~/.local/state/omarchy/monitor-scaling.log records every change the scaling tool made, including which process asked for it.

Why it happens

Three separate mechanisms in 4.0.x can write over your layout.

The scale tool persists to the wrong place. bin/omarchy-hyprland-monitor-scaling applies the new scale live with hyprctl eval, then tries to save it by rewriting either local omarchy_monitor_scale or the wildcard output = "" rule. Both are global. nico-kovacs showed in #6673 that setting a scale on one screen therefore changes the others within a second or two, because the file write itself triggers a config reload. If your file has explicit per-output rules instead, RonRayReed found in #8103 that the save silently does nothing, and Douda reported the same revert in #7242.

The clamshell watcher re-asserts the internal panel. omarchy-hyprland-monitor-watch runs omarchy-hyprland-monitor-clamshell on every monitor event, and every two seconds for as long as a laptop has an active external monitor. That script parses monitors.lua with sed. It matches only a rule written literally as output = "eDP-1", on one line. mkelk showed in #7084 that a desc: rule, or a rule split over several lines, is invisible to it, so it falls back to the catch-all’s scale and forces that onto the panel whenever the live value differs. On 4.0.0 a catch-all still at "auto" fell through further to a hardcoded 2. 4.0.1 stopped that, but the catch-all becomes a number the first time any scale button is pressed, and from then on an unmatched panel snaps back about a second after every change.

Position is never read from the catch-all. skoom21 documented in #7326 that the clamshell script’s read_monitor_position returns auto whenever it cannot find a connector-name rule for the internal panel, and that the live hyprctl eval inside the scale tool hardcodes position = "auto" as well. The watcher only re-applies position as a side effect of correcting the scale, so on a stock monitors.lua, which contains no per-output rule at all, a deliberate offset goes the moment the watcher decides the panel’s scale is wrong, and on every scale press regardless. reppiz saw the same rearrangement on 3.4.0 in #4785, so the position half predates Quattro.

One piece did get fixed. PR #7581 by fuchsblau merged on 2026-08-22 and shipped in 4.0.1 as “Leave an auto-scaled internal panel alone in clamshell recovery”. It makes the recovery step return early when the configured scale is not a number, which is the default "auto", and PedroMiguelInacio’s #6909 was closed minutes after it merged. The persistence PRs have not landed: #7437 was still open on 2026-09-16, and #8145 was closed unmerged on 2026-09-17 and folded into #12263, which is open.

If that did not work

You keyed a monitor by description. desc: is valid Hyprland syntax and Hyprland honours it, but the clamshell script does not. Give the internal panel a connector-name rule instead. mkelk’s reasoning in #7084 is that eDP numbering holds across hotplug and it is DP connectors that renumber, which is what desc: exists to survive. So use desc: for external screens if you need it and keep the internal panel literal.

You generated the rules with a Lua loop. In a comment on #8103, gfk reported that this makes things worse, because the shell parser finds no literal line and falls back to the catch-all on every monitor event and idle-wake. Keep at least the internal panel’s rule as one plain line.

Your monitors.lua is a symlink into a dotfiles repo. FCygan reported in #7625 that sed -i without --follow-symlinks replaces the symlink with a regular file the first time a scale button is pressed, so the repo quietly stops driving the config. Check with ls -l ~/.config/hypr/monitors.lua after any scale change.

Rotation comes back wrong after a reboot. YuseiRun reported in #7066 that a transform value in the config is present but not applied until you change it and change it back. That report is one machine, with transform set on the catch-all rule and the scale quoted as a string, and nobody else has confirmed it, so treat it as thin evidence rather than a confirmed pattern.

Nothing responds to the keyboard after your edit. A Lua error in monitors.lua aborts evaluation before the bindings load. See the nil global o page, and recover the shipped file with omarchy-refresh-config hypr/monitors.lua, which backs your version up first.

The screen comes back blank rather than misplaced. That is a different failure. Try suspend and resume or the dock notes.

Upstream threads about this error

76 issues on the Omarchy tracker match this error cluster. Newest fixes often appear as comments on the most-discussed threads.

IssueStateCommentsOpened
#6909 [Quattro] eDP-1 monitor scaling forces 2x reset on mixed-monitor array with Quickshell navbar · fixed by #7581 closed132026-08-14
#8113 Omarchy unusable under VMware Workstation with 3D acceleration enabledclosed102026-08-24
#7025 omarchy-menu-keybindings hangs forever when a user Lua config iterates hl.get_monitors()open92026-08-15
#12083 4K@120 HDMI screen blanks for seconds on every new frame after linux-omarchy 7.2.5-3 (AMD Navi 33)open92026-09-16
#6673 [Quattro] Display panel scale is per-monitor at runtime but persists globally, rescaling other monitors on reload · fixed by #5 open32026-08-10
#7084 Clamshell watcher ignores desc: rules for the internal panel and overwrites its scale every 2sopen42026-08-16
#7242 omarchy hyprland monitor scaling reverts instantly when monitors.lua has per-monitor rules · fixed by #5 closed42026-08-17
#7326 Internal monitor position cannot be made to stick: clamshell watcher and Display panel scaling both re-apply position = "auto"open42026-08-17
#8103 omarchy-hyprland-monitor-scaling doesn't persist scale on outputs with explicit per-monitor rules in monitors.luaclosed42026-08-24
#9804 Quickshell crashes with SIGSEGV in QSGRenderThread when Hyprland monitor is set to 10-bit (bitdepth = 10)open42026-09-02

Accepted answers upstream

Questions people ask

Why does my scale snap back about a second after I set it?
On a laptop with an external monitor active, omarchy-hyprland-monitor-watch runs omarchy-hyprland-monitor-clamshell every two seconds. That script reads monitors.lua and re-applies the internal panel to the scale it finds there. If the Display panel did not write your new value into the file, the poll undoes it.
Can I use nwg-displays or Hyprmon to arrange screens?
Use them to work out the layout, and the manual links Hyprmon. But the clamshell script reads only ~/.config/hypr/monitors.lua, and only single-line connector-name rules in it. nwg-displays writes multi-line hl.monitor blocks to that file, which the parser cannot read (the layout in #6673, the parser limit in #7084), and Hyprmon writes its own hyprmon.lua, which the script never opens (siebertm in #7084). Copy the numbers into monitors.lua as one-line hl.monitor rules to make them stick.
Does any 4.0.x release fix this?
Only partly. 4.0.1 shipped PR #7581, which stops the clamshell recovery fighting a panel whose scale is left at auto. The persistence bugs in omarchy-hyprland-monitor-scaling were still open on 2026-09-16. PR #7437 is unmerged, and PR #8145 was closed without merging on 2026-09-17 and folded into PR #12263, also unmerged.

Sources and credit

Fixes on this page were worked out by RonRayReed (Traced the two-second clamshell poll re-applying the stale scale from monitors.lua), mkelk (Showed that the watcher cannot read a desc: rule and asserts a guessed scale instead), skoom21 (Found the two code paths that hardcode position = auto for the internal panel), nico-kovacs (Showed that a per-monitor scale change persists globally and rescales the other screens), syskey8 (Explained the cursor dead zone caused by absolute positions under fractional scaling). Text here is our own paraphrase; follow the links for the original threads.

Unofficial. Verify against the official manual for your version. Improve this page Markdown version Sources