Frequently Asked Questions (FAQ)
August 2, 2026 · View on GitHub
How do I choose the platform backend?
All UI operations go through Desktop.Platform, which delegates to a single backend module. Public APIs (Desktop.Window, Desktop.Menu, etc.) are unchanged — only the implementation underneath varies.
Automatic (default)
config :desktop, :backend, :auto
Desktop.Platform.backend/0 picks:
| Condition | Backend |
|---|---|
config :desktop, :mobile_target, true (compile time) or Desktop.OS.mobile?/0 (runtime ELIXIR_DESKTOP_OS) | Desktop.Backend.Json |
NO_WX is set, or OTP :wx is not available | Desktop.Backend.Browser |
| Otherwise | Desktop.Backend.Wx |
Explicit config
In config/config.exs (or environment-specific config):
config :desktop, :backend, :wx # native wxWidgets window + webview
config :desktop, :backend, :json # JSON/TCP bridge (mobile native host)
config :desktop, :backend, :browser # OS default browser, no native window
For a custom implementation, set the backend to a module that implements the Desktop.Platform.Window, Content, Notification, Media, System, and Menu behaviour callbacks:
config :desktop, :backend, MyApp.DesktopBackend
Third-party backends that ship their own menu adapter (for example desktop_webview) should also set:
config :desktop, :menu_adapter, DesktopWebview.Menu.Adapter
Desktop.Platform.Menu.adapter/1 prefers config :desktop, :menu_adapter when present, then falls back to Wx / Json / DBus / Browser selection.
Restart the app after changing backend config — the router reads Application.get_env(:desktop, :backend, :auto) at runtime.
Environment variables
NO_WX=1— with:auto, forcesDesktop.Backend.Browser. Useful for headless servers, CI without a display, or local development when wxWidgets is not installed.BRIDGE_PORT— TCP port where the native host listens forDesktop.Backend.JsonRPC (see mobile bridge below). Use0for the in-process mock transport (tests).
Capabilities
Inspect what the active backend supports:
Desktop.Platform.backend() # e.g. Desktop.Backend.Wx
Desktop.Platform.capabilities() # %{window: true, content: :webview, ...}
Desktop.Platform.System.locale()
Desktop.Platform.System.os_description() # replaces :wx_misc.getOsDescription/0
Desktop.Platform.System.custom_event(:share, [path]) # mobile bridge custom events
Desktop.Window.reload(pid) # replaces :wxWebView.reload/1
| Backend | window | content | menu |
|---|---|---|---|
| Wx | yes | :webview | :wx or :dbus (Linux SNI) |
| Json | yes | :native (host webview) | :native |
| Browser | no | :os_browser | :none |
On Linux with DBus SNI available, Wx may use :dbus for the taskbar menu instead of in-window wx menus.
How does the mobile (Android/iOS) bridge work?
On mobile targets, desktop uses Desktop.Backend.Json instead of OTP :wx. The Elixir side speaks the legacy JSON protocol over TCP to your native host app. Set BRIDGE_PORT to the port your host app listens on. Transport is built in as Desktop.Bridge.Transport — the separate bridge hex package is no longer required.
App-level native events (share, save, restart, etc.) use:
Desktop.Platform.System.custom_event(:share, [path, label])
This sends [:custom_event, event, args] over the same wire format the Hex Bridge GenServer used previously.
Override explicitly if needed:
config :desktop, :backend, :json
Can I compile without the :wx OTP application?
Yes. Android/iOS release builds set MIX_TARGET=android (or ios). desktop then:
- Regenerates
src/desktop_wx.erlviadesktop_wx_stub.exswhen Mix loads the project: on host with:wxin OTP it useswx/include/wx.hrl; on android/ios (or without wx headers) it writes header-free integer fallbacks. Erlang compilation of that file is skipped whenMIX_TARGETis nothost. - Uses
Desktop.Wxinteger fallbacks instead ofwx.hrlmacros. - Uses
Desktop.Wx.Recordsstubs instead ofRecord.extract(..., from_lib: "wx/include/wx.hrl").
On a host-only build without :wx in OTP, the same fallbacks apply when wx.hrl is missing.
Runtime uses Desktop.Backend.Json on mobile; you do not need wx installed to compile or release.
How do I run without wxWidgets?
Set NO_WX=1 to use Desktop.Backend.Browser under :auto: URLs open in the OS default browser and window/menu APIs degrade gracefully (notifications are logged).
To test the Wx backend on headless Linux, keep wx enabled and use a virtual display instead:
xvfb-run -a mix phx.server
Library contributors can run mix test.fast (no wx), xvfb-run -a mix test.wx, and mix test.guard — see AGENTS.md in the repo root.
How do I release and distribute my Desktop application?
Creating an Installer
To create a distributable installer for your Desktop application, use the following command:
mix desktop.installer
This command will create platform-specific installers for Windows, macOS, and Linux that you can distribute to your users.
About mix release
While mix release is a standard Elixir command for creating releases, it's not the recommended approach for Desktop applications. The mix release command creates a standalone Erlang release, but it doesn't include the platform-specific packaging and UI components needed for a Desktop application.
Distribution
After running mix desktop.installer, you'll find the installer files in your project's build directory. These are the files you should distribute to your users:
- Windows:
.exeinstaller file - macOS:
.dmgor.appbundle - Linux:
.AppImage,.deb, or.rpmpackage
Users can simply download and run these installers to install your application on their system.
Getting Started
If you're new to Elixir Desktop:
- Follow the Getting your Environment Ready Guide to set up your development environment
- Create your first app with the Your first Desktop App Guide
- When ready to distribute, run
mix desktop.installerto create platform-specific installers