Skip to content

Desktop App Arch: FastAPI + Web + pywebview⚓︎

A creative architecture for building desktop applications with shorter delivery time for a certain class of desktop tools.

Recently got a new way to build desktop applications. This is not a typical Qt desktop application. The core idea is:

  • BE: local FastAPI backend service
  • FE: Web pages with HTML, CSS, and JavaScript
  • Shell: open it inside pywebview to make it a desktop app.

The interesting part is that this is still a real installable desktop application, not “just a website in a browser”. In practice, the release pipeline can use:

  • GitHub Actions builds the app.
  • PyInstaller produces the executable.
  • Inno Setup creates the corresponding installer.

Code structure⚓︎

The minimal structure looks like this:

project/
  main.py                 # desktop launcher
  app/
    main.py               # FastAPI entrypoint
    modules/              # business logic for each miniapp
  web/
    home.html             # home page
    apps/                 # individual miniapp pages
    assets/               # icons, images, static files

Each layer has a very clear job:

  • main.py: starts the local service, then opens the desktop window.
  • app/main.py: exposes routes, static assets, and JSON APIs.
  • app/modules/*/service.py: contains rules, calculations, and validation.
  • web/apps/*.html: handles presentation and user interaction only.

Runtime flow⚓︎

sequenceDiagram
  actor User
  participant Launcher as main.py
  participant API as FastAPI / uvicorn
  participant Shell as pywebview
  participant UI as Web UI
  participant Service as service.py

  User->>Launcher: launch desktop app
  Launcher->>API: start local server
  API-->>Launcher: listen on 127.0.0.1:8005
  Launcher->>Shell: create desktop window
  Shell->>UI: load local page
  User->>UI: interact with forms / buttons
  UI->>API: call local HTTP API
  API->>Service: run rules / calculation / validation
  Service-->>API: return result
  API-->>UI: return JSON response
  UI-->>User: update the page

How it differs from Qt⚓︎

The main difference is not that both can build desktop software. The real difference is what sits at the center of the system.

flowchart LR
  subgraph A["This architecture"]
    direction TB
    A1["Desktop launcher"]
    A2["Web UI"]
    A3["HTTP API"]
    A4["Service layer"]
    A5["Rules / calculations"]
    A1 --> A2 --> A3 --> A4 --> A5
  end

  subgraph B["Qt architecture"]
    direction TB
    B1["QApplication / window"]
    B2["Widgets / QML"]
    B3["Signal-Slot"]
    B4["UI-owned logic or controller"]
    B5["Rules / calculations"]
    B1 --> B2 --> B3 --> B4 --> B5
  end

  A1 ~~~ B1
  A2 ~~~ B2
  A3 ~~~ B3
  A4 ~~~ B4
  A5 ~~~ B5
Dimension This architecture Qt architecture
UI layer HTML / CSS / JS QWidget / QML
Desktop shell pywebview Qt itself
Business entry HTTP API signal-slot
Extension model add page + API + service add widget + event wiring
System center local service native UI

In short:

  • Qt: the window is the center.
  • This approach: the service is the center.

Advantages⚓︎

This approach is especially useful when:

  • Fast Delivery: building screens with Web technologies is often faster than building them with Qt.
  • Easier iteration: UI changes can usually be made and tested more quickly with familiar HTML, CSS, and JavaScript workflows.
  • Decoupled: the UI and logic are cleanly separated by HTTP APIs explicitly.
  • Better extensibility: adding a new miniapp usually means adding one page, one API, and one service module.
  • UI framework flexibility: the UI can be built with whatever Web framework or library best fits the project.

Disadvantages⚓︎

This architecture also comes with real trade-offs:

  • More moving parts: the launcher, local server, Web UI, and packaging pipeline all have to work together.
  • More complex debugging: problems may come from the desktop shell, frontend, backend, or the boundaries between them.
  • API boundary overhead: UI-to-business communication goes through HTTP-style interfaces instead of direct in-process calls.
  • Heavier startup: the application usually needs to initialize a local service before the UI becomes available.
  • Less natural for native-heavy apps: if the product depends heavily on native desktop widgets or deep OS integration, Qt can still be a better fit.