Why Separate the Wayland Compositor and Window Manager?
The Linux desktop’s move from X11 to Wayland has been a long-standing project aiming to simplify graphics, reduce latency, and resolve decades-old architectural problems. Traditionally, Wayland compositors have combined the roles of display server, compositor, and window manager into a single, monolithic process. This all-in-one approach solved input routing and rendering performance issues inherent in X11, but at a cost: it made customizing window management logic far more complex and discouraged experimentation and diversity in window manager design.
The River project—a non-monolithic Wayland compositor—breaks from this tradition. By splitting the window manager out into a separate client process, River allows window managers to be developed, swapped, and debugged independently of the compositor core. This separation is made possible by the river-window-management-v1 protocol, which gives full control over window placement, keybindings, server-side decorations, and other policy decisions to the external window manager, while the compositor remains focused on rendering, input routing, and performance guarantees.
This shift is not academic. For DevOps and SREs managing production Linux desktops or kiosks, the separation unlocks several tangible benefits:
- Crash resilience: A window manager crash no longer takes down the entire display server.
- Dynamic reconfiguration: Window managers (even written in high-level, garbage-collected languages) can be hot-swapped or updated without restarting the compositor or disrupting user sessions.
- Security: Policy and rendering can be sandboxed and upgraded independently, reducing attack surface.
- Lower barrier to entry: Developers can rapidly prototype new window management paradigms without the complexity of compositor internals.
But this architectural split is not without its own challenges—especially around protocol design, synchronization, and production hardening. The rest of this article unpacks these concerns with practical, production-focused guidance and real-world configuration examples.
Wayland Architecture: Monolithic vs. Modular
To understand the implications of separating compositor and window manager, it’s essential to contrast the two models. The table below summarizes the key differences:
| Aspect | Monolithic Compositor (e.g., Sway, Weston) | Modular Compositor (e.g., River + External WM) |
|---|---|---|
| Window Management | Implemented inside the compositor process; tightly coupled | Separate client process communicates via protocol (e.g., river-window-management-v1) |
| Crash Impact | Window manager crash brings down the compositor/session | Window manager crash can be recovered without losing session |
| Extensibility | Requires forking or patching the compositor | New window managers can be developed and swapped independently |
| Language Support | Typically C/C++/Rust; garbage collection risky due to latency | Can use high-level languages safely (latency isolated from compositor) |
| Performance | Potentially lower IPC overhead, but harder to isolate slow code | Minimal IPC overhead; “frame perfection” achievable with careful protocol design |
| Security | All policy and rendering in one process; larger attack surface | Policy can be sandboxed, reducing compositor’s privileges |
Reference: Isaac Freund, River project
Protocol Challenges: Frame Perfection and Latency
The critical challenge in modularizing window management is maintaining frame perfection—ensuring that window changes (e.g., tiling layout updates) are applied atomically, avoiding flicker, gaps, or input lag. The river-window-management-v1 protocol addresses this by batching state changes and synchronizing rendering only when all windows have submitted new buffers, with short timeouts to avoid stalling the compositor. Unlike the X11 model (where async communication could lead to visible artifacts), River’s protocol ensures there are no extra round-trips on every frame or input event.
Production-Ready Configuration: Separating Compositor and Window Manager
Let’s walk through deploying River with an external window manager. We’ll focus on security, operational best practices, and realistic configurations—not just “hello world.”
1. Installing Dependencies
River is written in Zig and depends on wlroots, wayland, and other libraries. For production, use a recent LTS distribution and pinned package versions to avoid breakage:
# Ubuntu 24.04+ or Fedora 39+ recommended
sudo apt install zig wlroots-dev libxkbcommon-dev libevdev-dev libpixman-1-dev pkg-config
# For Xwayland compatibility (optional, but often needed):
sudo apt install xwayland
Note: River requires Zig 0.15 or later. Confirm with:
zig version
# Output should be >= 0.15
2. Building and Installing River
git clone https://github.com/gnuunixchad/river.git
cd river
zig build -Doptimize=ReleaseSafe --prefix ~/.local install
For system-wide install, use sudo or package River as an RPM/DEB with custom hardening flags (see PACKAGING.md).
3. Configuring River to Launch a Window Manager
On startup, River executes the script at $XDG_CONFIG_HOME/river/init (falls back to ~/.config/river/init). This script should launch your chosen window manager, set up environment variables, and start essential services (e.g., dbus, polkit agent).
#!/bin/sh
# ~/.config/river/init
# Hardening: run the window manager in a restricted user namespace
unshare -n -- bash -c '
export WAYLAND_DISPLAY=wayland-1
# Example: start tinyrwm (a minimal river-compatible window manager)
exec tinyrwm
'
# Start background services (replace with your actual agents)
dbus-run-session -- systemctl --user start polkit-gnome-authentication-agent-1.service
Security tips:
- Run the window manager with reduced privileges (no unnecessary CAP_*).
- Restrict file access using
systemd --userunits withProtectHome=yes,ProtectSystem=strict. - Never start Xwayland or legacy X clients unless absolutely necessary.
4. Example: Switching Window Managers on the Fly
One of the advantages of River is hot-swapping window managers without restarting the session. Assuming you have both tinyrwm and canoe installed, you can kill the current window manager and start another:
# Find and kill the current window manager (replace 'tinyrwm' if using another)
pkill -f tinyrwm
# Start canoe in the same session
canoe &
No windows or user sessions are lost in the process—only window management policy is swapped.
Operational Considerations: Monitoring, Security, and Hot-Swapping
Running a production Wayland session with a split compositor and window manager model introduces new operational challenges. Here’s how to address them:
Monitoring and Logging
- Configure
riverand your window manager to log tosystemd-journaldwithStandardOutput=journal. - Set up health checks to ensure both processes remain alive (e.g.,
systemd --userunits withRestart=on-failure). - Aggregate logs for both compositor and window manager for holistic visibility.
Security Hardening Checklist
- Use
seccompandAppArmorprofiles to sandbox the window manager process. - Run the compositor and window manager as the non-root user.
- If possible, use
user namespacesto further isolate window management logic. - Review upstream security advisories for Wayland protocol extensions in use.
Hot-Swapping and Upgrades
- Test window manager upgrades in a nested Wayland/X11 session before deploying to production (River supports running nested).
- Keep a fallback window manager binary available in case of failed upgrades.
- Automate window manager restart policies using
systemd --user:
[Unit]
Description=River Window Manager
[Service]
ExecStart=/usr/local/bin/tinyrwm
Restart=on-failure
ProtectSystem=full
ProtectHome=yes
PrivateTmp=yes
[Install]
WantedBy=default.target
Troubleshooting: Common Errors and Solutions
Splitting the compositor and window manager can introduce new classes of failure. Here are the most common, with actionable fixes:
- Window manager does not start or crashes immediately:
- Check the
riverlog and the window manager’s stdout/stderr for protocol version mismatches. - Ensure the window manager supports the
river-window-management-v1protocol version your compositor provides. Upgrade/rebuild as necessary.
- Check the
- No windows managed or keybindings unresponsive:
- Verify that the window manager is running (e.g.,
ps aux | grep tinyrwm). - Check your
initscript for typos or failed background service launches. - Ensure input devices are correctly configured in
river(useriverctlfor runtime inspection).
- Verify that the window manager is running (e.g.,
- Visual artifacts, flicker, or layout gaps:
- If using a custom window manager, check its buffer submission and state batching logic. Delays in buffer updates can cause temporary gaps.
- Refer to design documentation on “frame perfection.”
- “Permission denied” errors launching Xwayland clients:
- Make sure Xwayland is installed and configured for non-root users.
- Limit Xwayland launch to only trusted applications; do not run X clients as root.
- Input devices not working:
- Check device permissions (
/dev/input/*should be accessible to the user runningriver). - Use
udevrules to ensure persistent device access.
- Check device permissions (
Trade-offs and Alternatives
While River’s approach is the most advanced split-compositor model in production today, it’s not the only one. Here’s how alternatives stack up:
| Compositor/WM | Architecture | Benefits | Drawbacks |
|---|---|---|---|
| River + External WM | Modular (split) | Crash resilience, language flexibility, hot-swapping, lower entry barrier | Protocol maturity, fewer “fancy” shell features, limited VR/3D support |
| Sway | Monolithic | Mature, i3-like, robust wlroots integration | Must fork for major WM changes; WM crash loses session |
| Weston | Monolithic | Reference compositor, stability | Customization requires patching core |
| Musa | Hybrid (external WMs supported, early stage) | First-class multiseat, WM extensibility | Less mature, smaller ecosystem |
For most production deployments, River is currently the only split-compositor viable for daily use, but this will likely change as protocol maturity and window manager diversity increase.
Key Takeaways
Key Takeaways:
- Separating the Wayland compositor and window manager makes Linux desktop and kiosk deployments more resilient, flexible, and secure.
- The river-window-management-v1 protocol enables frame-perfect, low-latency window management by batching state changes and decoupling policy from rendering.
- Crash recovery, hot-swapping window managers, and language flexibility are immediate operational benefits—but require careful protocol and process management.
- Security hardening is essential: sandbox window managers, avoid unnecessary privileges, and monitor for protocol compatibility and process health.
- Alternatives like Sway (monolithic) offer stability and ecosystem maturity, but at the cost of extensibility and resilience.
For further reading on protocol details, configuration, and the River project’s roadmap, see Isaac Freund’s blog and the River GitHub repository.

