@stlite/desktop
@stlite/desktop allows you to convert your Streamlit application into a desktop app with Stlite runtime, a Pyodide-based Wasm-port of Streamlit.
Quick Start
Section titled “Quick Start”1. Initialize Project
Section titled “1. Initialize Project”Create a package.json file for your new project:
{ "name": "my-app", "version": "0.1.0", "main": "./build/electron/main.js", "scripts": { "dump": "dump-stlite-desktop-artifacts", "serve": "cross-env NODE_ENV=production electron .", "app:dir": "electron-builder --dir", "app:dist": "electron-builder", "postinstall": "electron-builder install-app-deps" }, "build": { "files": [ "build/**/*" ], "directories": { "buildResources": "assets" } }, "devDependencies": { "@stlite/desktop": "^0.92.1", "cross-env": "^7.0.3", "electron": "34.3.0", "electron-builder": "^25.1.8" }, "stlite": { "desktop": { "files": [ "app.py" ], "entrypoint": "app.py" } }}Run installation:
npm install# oryarn install2. Create Application
Section titled “2. Create Application”Create app.py:
import streamlit as st
st.write("Hello from Stlite Desktop!")3. Build & Run
Section titled “3. Build & Run”Dump artifacts (prepare build):
npm run dumpPreview:
npm run serveDistribute:
npm run app:distThis generates the application files (.app, .exe, etc.) in the dist directory.
Configuration
Section titled “Configuration”Configure your app via the stlite.desktop section in package.json.
Files and Dependencies
Section titled “Files and Dependencies”"stlite": { "desktop": { "files": ["app.py", "pages/*.py", "assets"], "entrypoint": "app.py", "dependencies": ["numpy", "pandas"], "requirementsTxtFiles": ["requirements.txt"] }}- files: Files and directories to include.
- entrypoint: The main script to run.
- dependencies: List of packages to install.
- requirementsTxtFiles: List of
requirements.txtfiles to install.
UI Customization
Section titled “UI Customization”Hide the toolbar and hamburger menu (Embed mode):
"stlite": { "desktop": { "embed": true }}File System & Persistence
Section titled “File System & Persistence”IndexedDB Persistence
Section titled “IndexedDB Persistence”Mount an IndexedDB-backed directory to persist files across restarts.
"stlite": { "desktop": { "idbfsMountpoints": ["/mnt"] }}Local File Access (NODEFS)
Section titled “Local File Access (NODEFS)”To access the host OS file system, you need to enable NodeJS Worker Mode and mount directories using nodefsMountpoints.
"stlite": { "desktop": { "nodeJsWorker": true, "nodefsMountpoints": { "/mnt": "." } }}This mounts the current directory (.) of the host to /mnt in the virtual file system.
[!TIP] You can use placeholders like
{{home}},{{userData}},{{temp}}in the host paths.
NodeJS Worker Mode
Section titled “NodeJS Worker Mode”By default, Stlite executes Python code on Pyodide running in a Web Worker dispatched by the renderer process. The renderer process is a browser process, so it’s sandboxed from the host OS.
When you set nodeJsWorker to true, Stlite dispatches the worker as a Node.js Worker Thread that runs in the main process. This enables features that require direct access to the host system, such as NODEFS.
"stlite": { "desktop": { "nodeJsWorker": true }}Full JavaScript/Node.js Access
Section titled “Full JavaScript/Node.js Access”In NodeJS worker mode, the Python code has full access to the Node.js JavaScript environment through Pyodide’s js module and pyodide.code.run_js(). This allows you to call any Node.js API directly from Python.
For example, you can execute shell commands:
import pyodide
result = pyodide.code.run_js('''require("child_process").execSync("whoami").toString().trim()''')print(result) # Prints the current usernameThis opens up powerful possibilities for desktop applications, such as:
- Running system commands and scripts
- Accessing Node.js native modules
- Integrating with other system tools and services
However, this also means your Python code has the same level of access as any Node.js application running on the user’s machine. See the Security Considerations below.
Security Considerations
Section titled “Security Considerations”When NodeJS worker mode is enabled, the Python code executes within a Node.js worker thread in the main process. This means:
- The Python code has the same privileges as the Node.js process itself. It can access the file system, spawn child processes, make network requests, and perform any operation that Node.js can do.
- There is no sandbox. Unlike the default Web Worker mode (which runs in a browser-like sandboxed environment), NodeJS worker mode provides no isolation between your Python code and the host operating system.
- You are responsible for the security of your app. If your app executes untrusted Python code or loads untrusted packages, those could potentially harm the user’s system.
This is an intentional design to enable powerful features like direct file system access via NODEFS. However, you should only use this mode when you trust all Python code and packages that your app will execute.
Limitations
Section titled “Limitations”- External Links: Navigation to external URLs (e.g.
st.markdown("[link](https://...)")) is restricted for security.