Fix WezTerm on Windows: Multi-Monitor DPI, Transparency & Performance
Fix WezTerm rendering on Windows multi-monitor setups. Solve DPI glitches, transparency issues, and acrylic lag. Full working .wezterm.lua config included.
In This Guide click to collapse
I run WezTerm on Windows with a mixed-DPI multi-monitor setup: a 4K display flanked by two 1080p monitors. After weeks of dealing with rendering glitches, broken transparency, and drag lag, I finally nailed the three config lines that fix everything.
This guide documents every problem I hit, every fix I tried (including the ones that failed), and the final working .wezterm.lua configuration you can copy-paste.
TL;DR: The Three Lines That Fix Everything
config.front_end = 'OpenGL' -- fixes transparency
config.window_background_opacity = 0.95 -- native see-through
config.dpi = 144.0 -- fixes multi-monitor DPI glitch
The Setup: Mixed DPI Multi-Monitor on Windows
My desk runs three monitors at different resolutions and scaling factors. This is a common setup for developers, and it’s exactly where WezTerm’s default settings break down.
| Position | Model | Resolution | Windows Scaling | Effective DPI |
|---|---|---|---|---|
| Top | Philips 241V8 | 1920×1080 | 100% | 96 |
| Front (primary) | LG HDR 4K | 3840×2160 | 150% | 144 |
| Right | BenQ GL2460 | 1920×1080 | 100% | 96 |
The key detail: the DPI jump between my primary 4K monitor (144 DPI) and the side 1080p monitors (96 DPI) is what triggers every rendering issue in WezTerm. Windows fires a WM_DPICHANGED event when a window crosses this boundary, and WezTerm doesn’t handle it gracefully.
WezTerm version: 20240203-110809-5046fc22 (stable release as of February 2024; WezTerm has active nightly builds and periodic stable releases, so check wezterm.org for the latest version).
Problem 1: DPI Rendering Glitch Between Monitors
What Happens
Dragging WezTerm from the 4K monitor to the right 1080p monitor causes a visible rendering glitch at the monitor boundary. The window partially redraws, text reflows at the wrong scale, and the terminal becomes unusable until you stop moving it.
Interestingly, dragging between the top 1080p monitor and the 4K monitor works fine. Both transitions happen at the same vertical pixel boundary. The problem is specific to the right monitor because of its vertical offset (y=1625 vs the 4K at y=1080), which causes a misaligned resize rect during the DPI transition.
Root Cause
When WezTerm crosses from a 150%-scaled monitor to a 100%-scaled monitor, Windows sends a WM_DPICHANGED message telling the app to resize and re-render at the new DPI. WezTerm’s renderer tries to handle this per-monitor DPI change mid-drag, but the combination of different DPI values (144 → 96) and the vertical offset of the right monitor triggers a buggy re-render.
The Fix: Lock DPI to Your Primary Monitor
-- Force DPI to your primary monitor's value
-- 150% scaling = 144 DPI (96 × 1.5)
config.dpi = 144.0
This tells WezTerm to render at a fixed DPI regardless of which monitor it’s on. The WM_DPICHANGED event still fires, but WezTerm ignores it because the DPI is locked.
Trade-off
Text will render at 150% scale on your 1080p monitors, slightly larger than native. For me this is barely noticeable and a worthwhile trade for zero rendering glitches.
Two other settings help smooth things out:
-- Prevent window resize when DPI changes
config.adjust_window_size_when_changing_font_size = false
-- Smoother font rendering across DPI boundaries
config.freetype_load_flags = 'NO_HINTING'
Problem 2: Transparency Not Working (WebGpu Bug)
Symptoms
Setting window_background_opacity to any value below 1.0 has zero visible effect. The background stays solid black. No see-through transparency at all.
This is a known WebGpu bug on Windows. Instead of making the window transparent, WebGpu just darkens it toward black. The issue has been reported multiple times:
WebGpu vs OpenGL on Windows
| Feature | WebGpu | OpenGL |
|---|---|---|
| Window transparency | Broken (darkens to black) | Works natively |
| DPI transitions | Slightly smoother | Fine with DPI lock |
| GPU acceleration | Modern API (DirectX 12) | Legacy but stable |
| Performance | Comparable | Comparable |
| Maturity on Windows | Newer, more bugs | Battle-tested |
The Fix: Switch to OpenGL
-- OpenGL natively supports window transparency on Windows
-- WebGpu does NOT (confirmed bug)
config.front_end = 'OpenGL'
-- Now this actually works!
config.window_background_opacity = 0.95 -- 5% see-through
Important
Changing the front_end setting requires a full WezTerm restart. It will not hot-reload like other config changes. Close all WezTerm windows and relaunch.
Problem 3: Acrylic & Mica Backdrop Lag
What I Tried
Before discovering the OpenGL fix, I tried using Windows’ built-in backdrop effects as a workaround for the WebGpu transparency bug:
-- DON'T DO THIS - causes severe lag
config.win32_system_backdrop = 'Acrylic' -- or 'Mica'
What Happened
- Acrylic: No real see-through transparency, plus severe input lag and window drag stutter
- Mica: Only tints the window with the desktop wallpaper color (not truly transparent), plus similar drag lag
- Acrylic + FPS caps (
max_fps = 60,animation_fps = 1): Still severe lag
Root Cause
Both Acrylic and Mica route rendering through the Windows DWM (Desktop Window Manager) compositor. On multi-monitor setups, the compositor overhead causes noticeable lag during window operations. This is a Windows limitation. No amount of FPS capping or WezTerm config tuning can fix it.
The Fix: Don’t Use Backdrop Effects
Simple window_background_opacity with the OpenGL backend gives you true transparency without any DWM compositor overhead. Remove any win32_system_backdrop settings from your config.
Quick Diagnostic Flowchart
Is your WezTerm having issues on Windows?
Terminal glitches when dragged between monitors?
→ Add config.dpi = 144.0 (replace 144 with your primary monitor’s DPI: scaling% × 96 ÷ 100)
Transparency / opacity not working?
→ Switch to config.front_end = 'OpenGL' (WebGpu transparency is broken on Windows)
Window lags when dragging?
→ Remove any win32_system_backdrop setting (Acrylic/Mica cause DWM lag)
Config changes not taking effect?
→ Fully restart WezTerm (backend changes like front_end don’t hot-reload)
Full Test Matrix: Everything I Tried
Here’s every combination I tested so you don’t have to:
| # | Backend | Opacity | Backdrop | FPS Caps | Transparency | Drag Lag | Verdict |
|---|---|---|---|---|---|---|---|
| 1 | WebGpu | 0.5 | None | No | Pure black | None | Failed |
| 2 | WebGpu | 0.5 | Acrylic | No | None | Severe | Failed |
| 3 | WebGpu | 0.5 | Mica | No | Wallpaper tint only | Severe | Failed |
| 4 | WebGpu | 0.95 | Acrylic | Yes | None | Severe | Failed |
| 5 | OpenGL | 0.95 | None | No | Working | None | Winner |
The only combination that works: OpenGL backend + simple opacity + no backdrop effects.
The Complete Working Configuration
Here’s my full .wezterm.lua with all the fixes applied. Copy this to %USERPROFILE%\.wezterm.lua on Windows.
local wezterm = require 'wezterm'
local config = wezterm.config_builder()
local act = wezterm.action
-- ============================================================
-- FONT
-- ============================================================
config.font = wezterm.font_with_fallback({
{
family = 'Maple Mono NF',
weight = 'Bold',
harfbuzz_features = { 'calt=1', 'liga=1' }, -- ligatures on
},
{ family = 'JetBrainsMono Nerd Font', weight = 'Bold' },
'Noto Color Emoji',
})
config.font_size = 11.0
-- ============================================================
-- SHELL (WSL as default)
-- ============================================================
config.default_domain = 'WSL:Ubuntu' -- change Ubuntu to your WSL distro name (run `wsl -l -v` to list)
-- ============================================================
-- RENDERING BACKEND
-- OpenGL supports native window transparency on Windows.
-- WebGpu does NOT. Confirmed bugs #5790, #4502, #3998.
-- ============================================================
config.front_end = 'OpenGL'
-- ============================================================
-- THEME & APPEARANCE
-- ============================================================
config.color_scheme = 'Catppuccin Mocha'
config.window_background_opacity = 0.95 -- 5% see-through
config.window_padding = { left = 8, right = 8, top = 8, bottom = 8 }
-- ============================================================
-- TAB BAR & WINDOW CHROME
-- ============================================================
config.hide_tab_bar_if_only_one_tab = false
config.use_fancy_tab_bar = true
config.window_decorations = "INTEGRATED_BUTTONS|RESIZE"
-- ============================================================
-- CURSOR
-- ============================================================
config.default_cursor_style = 'BlinkingBar'
config.cursor_blink_rate = 500
-- ============================================================
-- SCROLLBACK & UNICODE
-- ============================================================
config.scrollback_lines = 10000
config.unicode_version = 14
config.treat_east_asian_ambiguous_width_as_wide = false
-- ============================================================
-- MULTI-MONITOR DPI FIX
-- Lock DPI to primary monitor (150% = 144 DPI).
-- Prevents WM_DPICHANGED re-render glitches when crossing
-- between monitors with different scaling factors.
-- ============================================================
config.dpi = 144.0
config.adjust_window_size_when_changing_font_size = false
config.freetype_load_flags = 'NO_HINTING'
-- ============================================================
-- MISC
-- ============================================================
config.audible_bell = 'Disabled'
config.keys = {
{ key = 'v', mods = 'CTRL', action = act.PasteFrom 'Clipboard' },
{ key = 'c', mods = 'CTRL|SHIFT', action = act.CopyTo 'Clipboard' },
}
config.set_environment_variables = {
LANG = 'en_US.UTF-8',
LC_ALL = 'en_US.UTF-8',
LANGUAGE = 'en_US:en',
}
return config
Configuration Breakdown
| Setting | Value | Why |
|---|---|---|
front_end |
'OpenGL' |
Only backend with working transparency on Windows |
window_background_opacity |
0.95 |
Subtle see-through effect without readability loss |
dpi |
144.0 |
Locks rendering to 4K monitor DPI, prevents multi-monitor glitches |
adjust_window_size_when_changing_font_size |
false |
Prevents window resizing on DPI change |
freetype_load_flags |
'NO_HINTING' |
Smoother font rendering across DPI boundaries |
default_domain |
'WSL:Ubuntu' |
Opens WSL by default instead of PowerShell |
color_scheme |
'Catppuccin Mocha' |
Clean dark theme with good contrast |
window_decorations |
'INTEGRATED_BUTTONS|RESIZE' |
Integrated title bar with tab bar |
How to Calculate Your DPI Value
If your primary monitor uses a different scaling factor, calculate your DPI like this:
DPI = (Windows scaling percentage / 100) × 96
Find your scaling percentage at:
Settings > System > Display > Scale
Examples:
100% scaling → 96 DPI
125% scaling → 120 DPI
150% scaling → 144 DPI
175% scaling → 168 DPI
200% scaling → 192 DPI
If You Need to Roll Back
| To Undo | Do This |
|---|---|
| Transparency | Remove window_background_opacity or set to 1.0 |
| DPI lock (text too large on 1080p) | Remove config.dpi = 144.0, but multi-monitor glitch may return |
| Switch back to WebGpu | Set config.front_end = 'WebGpu' and add config.webgpu_power_preference = 'HighPerformance', but transparency will stop working |
FAQ
Why not just use WebGpu?
WebGpu is the newer rendering backend and handles some DPI transitions slightly better. However, it has a confirmed bug on Windows where window_background_opacity doesn’t create true transparency; it just darkens the background to black. Until this is fixed upstream, OpenGL is the only option for window transparency on Windows.
Does switching to OpenGL hurt performance?
No. In my testing, OpenGL and WebGpu perform identically for terminal rendering. The difference is in API maturity. OpenGL is older but has better Windows compositor integration. You won’t notice any difference in scrolling speed, frame rate, or responsiveness.
Will locking DPI make text blurry on my 1080p monitors?
Not blurry, just slightly larger. When you lock DPI to 144 (150% scaling), text on your 1080p monitors renders as if they were also at 150% scaling. The text is sharp and clear, just scaled up. Combined with freetype_load_flags = 'NO_HINTING', the rendering is smooth across all monitors.
Can I use Acrylic transparency without the drag lag?
No. The lag comes from the Windows DWM compositor, not from WezTerm. There’s no WezTerm setting that can fix it. If you want transparency without lag, use window_background_opacity with the OpenGL backend. It bypasses DWM entirely.
Does this fix work on Linux or macOS?
These specific issues are Windows-only. Linux (X11/Wayland) and macOS have different compositing systems. On Linux, both WebGpu and OpenGL handle transparency correctly. On macOS, the native window compositor handles it. The DPI lock fix is only relevant if you have mixed-DPI monitors.
What WezTerm version do I need?
These fixes work on version 20240203-110809-5046fc22, which is the latest stable release as of February 2026. The config.dpi setting was introduced in earlier versions, and front_end has been available since the WebGpu backend was added. Any recent WezTerm version should work.
I changed front_end but nothing happened?
The front_end setting does not hot-reload. You must fully close all WezTerm windows and relaunch the application. Other settings (like window_background_opacity and color_scheme) hot-reload on save.
How do I check which rendering backend is active?
Open WezTerm’s debug overlay with Ctrl+Shift+L, then look for the front_end line in the output. It will show either OpenGL or WebGpu.
