Desktop Applications (lila desktop)
A Lila app is a normal ASGI application, so it can also run inside a native window: the server
starts on a local port and the OS webview (WebView2/WebKit) renders it. Measured footprint for the
Python side: import lila ≈ 19 MB RSS and a full App ≈ 42 MB; the window
itself uses the webview already installed in the operating system instead of bundling a browser.
1. Running in Desktop Mode
lila desktop dev loads .env, finds a free port, starts Uvicorn in a
daemon thread and opens a native window. It binds only to 127.0.0.1, allows a
single instance and gates the session with a per-run token that is exchanged for an
HttpOnly cookie on the first navigation:
# Starts Uvicorn in a daemon thread and opens a native window
lila desktop dev
# Custom options:
lila desktop dev --title "My Desktop App" --width 1280 --height 850
- Preferred (
pywebview): Uses Microsoft WebView2 on Windows, WebKit on macOS, and WebKitGTK on Linux. Install with:pip install "lila-framework[desktop]" - Fallback: if pywebview is not installed, Lila detects Edge, Chrome or Brave and launches an isolated standalone
--appwindow; if none is found it opens the default browser.
2. Compiling Standalone Executables (.exe / Binary)
lila desktop build writes a temporary bootstrap that imports main
statically (so PyInstaller can see your code), then bundles main, app and
Lila's data files (--collect-all lila), plus public/ and
resources/ when they exist. Output goes to dist/<name>.
# Install packaging dependencies:
pip install pyinstaller pywebview
# or: pip install "lila-framework[desktop]"
# Build a single-file executable:
lila desktop build --name "InvoiceManager" --onefile --windowed
# Onedir build (faster startup, easier to inspect):
lila desktop build --name "InvoiceManager" --onedir
# The compiled binary is ready in dist/InvoiceManager (InvoiceManager.exe on Windows).
3. Packaging Assets and PyInstaller sys._MEIPASS
Lila's lila.core.config resolves read-only assets through
get_base_path() (honoring sys._MEIPASS when frozen) and writable files
(SQLite database, cache, logs) through get_data_path(). In a frozen build the
writable location is the OS application-data directory
(%LOCALAPPDATA%\\<title> on Windows, ~/Library/Application Support/<title>
on macOS, $XDG_DATA_HOME/<title> on Linux), not the read-only executable folder.
On a frozen build, Lila looks for .env in that application-data directory first
(then the current working directory) and keeps the SQLite database, cache and logs there.
Keep DB_NAME relative (DB_NAME="lila") so it resolves under that
directory.