Minimal starter for packaging Django inside Electron.
Project description
Desktop Django Starter
Minimal, attendee-facing starter for shipping a Django app inside Electron with a bundled Python runtime.
Documentation: desktop-django-starter.readthedocs.io
This repository now includes a runnable development slice, a staged packaged-backend slice, and a sign/notarization-aware GitHub packaging slice: a tiny Django app served locally and supervised by Electron, with a bundled Python runtime staged under electron/.stage/backend/python/ and packaged desktop artifacts built in GitHub Actions.
Intent
- Be the canonical teaching repo for the DjangoCon Europe 2026 talk/blog cycle.
- Stay minimal, generic, and easy to adapt to an existing Django app.
- Show the hard parts people should not have to rediscover from scratch: process lifecycle, local runtime packaging, localhost boot, and cross-platform expectations.
- Use
djdeskas reference material for packaging/build patterns only, not as the starter baseline.
Current Status
Runnable starter slices:
- Django 6.0.3 project under
src/desktop_django_starter/ - tiny server-rendered CRUD demo app under
src/example_app/ - background task visualization demo under
src/tasks_demo/with animated pulse-ring indicators, polling-based live updates, and realdjango_tasksexecution backed by SQLite - Electron 40 shell under
electron/ - experimental Tauri 2 shell under
tauri/ - random-port localhost startup with
/health/readiness polling - minimal preload bridge for opening the app-data folder
- staged packaged-backend flow under
electron/.stage/backend/with a bundled Python runtime, installed app dependencies, collected static assets, anddesktop_django_starter.settings.packaged - packaged-like Electron launcher that exercises the staged bundled-runtime contract locally, including the supervised task worker
- on-demand GitHub Actions packaging for macOS, Windows, and Linux, with downloadable workflow artifacts, per-platform SHA-256 checksum files, env-driven macOS signing/notarization scaffolding, optional Windows signing inputs, and
justhelpers for triggering and fetching them
Auto-update and full production release automation are still deferred. The current slice is intended to make release signing/notarization expectations explicit without making unsigned local packaging unusable.
Docs
docs/specification.md: main product and technical specificationdocs/architecture.md: intended runtime model and draft repo shapedocs/decisions.md: repo-local decisions captured from the initial planning passdocs/release.md: packaging secrets, installer artifacts, and connected/offline manual update guidancedocs/agent-use.md: how coding agents should consume this repo and reuse its skill
The docs are built with Sphinx over the Markdown sources in docs/ and are intended to be publishable on Read the Docs.
Agent Consumers
llms.txt: concise repo entry point for coding agentsskills/wrap-existing-django-in-electron/SKILL.md: reusable workflow for adapting an existing Django project to an Electron shelldocs/agent-use.md: agent-oriented usage notes and guardrails
Development
just install: install the local environment withuvjust migrate: apply the local SQLite migrationsjust backend-dev: run the Django app directly on127.0.0.1:8000just task-worker: run the single background task worker for/tasks/without Electronjust electron-install: install Electron dependenciesjust electron-start: start the Electron shell, which launches Django plus one background task worker on a random localhost portjust tauri-install: install the experimental Tauri shell dependenciesjust tauri-start: start the experimental Tauri shell against the repo checkoutjust tauri-smoke: start the experimental Tauri shell and auto-exit after the first page loadjust tauri-packaged-start: stage the packaged backend and start the experimental Tauri shell against that staged runtimejust tauri-packaged-smoke: stage the packaged backend, launch the experimental Tauri shell, and auto-exit after the first page loadjust tauri-build: stage the packaged backend and build a host-native Tauri bundle that embeds it as app resourcesjust tauri-build-smoke: stage the packaged backend, build a debug Tauri bundle, and launch the built app once with smoke-test auto-exit on hosts where the wrapper can run the bundle directlyjust packaged-stage: build the staged packaged-backend bundle underelectron/.stage/backend, including the bundled Python runtimejust packaged-start: rebuild the staged bundle and launch Electron in packaged-like mode against the staged bundled runtimejust packaged-smoke: rebuild the staged bundle and run a packaged-like Electron smoke launch that auto-exits after loadjust package-dist: build a local desktop package for the current host target (defaults to--mac dmg)just package-dist-dir: build an unpacked local desktop app for the current host targetjust github-package: trigger the GitHub Actions cross-platform packaging workflow for the current branchjust github-package-download <run-id>: download a specific packaging workflow run intodist/github-actions/<run-id>/just github-package-latest-run: print the latest successful packaging workflow run id for the current branchjust github-package-latest-path: print the local path for the lastgithub-package-download-latestdownloadjust github-package-download-latest: download the latest successful packaging workflow run for the current branchjust dev: same asjust electron-startjust docs: build the docs and open the generated sitejust docs-serve: run a live-reloading local docs serverjust loc: print aclocsummary plus a per-directory code breakdown, with a Python fallback whenclocis absentjust test: run the Django and docs test suitejust build: build the Python package metadata scaffold
Quickstart
just installjust electron-installjust dev
For backend-only work, use just backend-dev.
When you need the real /tasks/ demo outside Electron, run just task-worker in a second terminal.
When you want to compare the shell swap directly, use just tauri-start after just tauri-install.
For the packaged-mode staging slice, use just packaged-start.
The electron/.stage/ directory is rebuilt on each packaged staging run and should be treated as ephemeral.
Experimental Tauri Option
The tauri/ directory is an experiment, not a parity shell.
- it reuses the same Django launcher contract: migrations, localhost health polling,
db_worker, and packaged settings just tauri-startruns against the repo checkout withuv run pythonjust tauri-packaged-startstill usestauri dev, but swaps in the staged backend underelectron/.stage/backendjust tauri-buildnow builds a real local Tauri bundle for the current host and includes the staged backend as bundled app resources- the built Tauri app resolves
backend/runtime-manifest.jsonand the bundled Python runtime from Tauri's packaged resource directory instead of repo-relative paths - the single-instance hook exists, but built-bundle second-launch behavior is still a manual verification item for this experiment
- dedicated Tauri release automation, signing/notarization wiring, and GitHub packaging workflow integration are still intentionally out of scope
For GitHub-built install artifacts, use just github-package and then just github-package-download-latest once the workflow succeeds. The download helpers require the GitHub CLI plus an authenticated gh session and place per-platform artifacts under dist/github-actions/<run-id>/. just github-package-latest-run prints the current latest run id, just github-package-download-latest prints the downloaded paths and records the run id in dist/github-actions/latest-run.txt, and just github-package-latest-path prints the local directory for that latest downloaded run.
Pass a different branch as the first argument when needed, for example just github-package my-branch.
The current workflow builds one architecture per platform: macOS arm64 on macos-latest, plus Windows x64 and Linux x64 on the hosted runners.
Packaging, Signing, and Manual Updates
Local packaging remains usable without any signing secrets:
just package-distbuilds a host-native installer artifact for the current machinejust package-dist-dirbuilds an unpacked app directory for local inspection
When signing credentials are present, electron-builder now uses them directly:
- macOS signing uses the normal
CSC_LINKorCSC_NAMEinputs plusCSC_KEY_PASSWORDwhen needed - macOS notarization is enabled only when a complete Apple credential set is present; the recommended path is
APPLE_API_KEYplusAPPLE_API_KEY_IDandAPPLE_API_ISSUER - Windows signing is optional and secret-driven;
WIN_CSC_LINKplusWIN_CSC_KEY_PASSWORDis the baseline path, with optional publisher/timestamp inputs documented indocs/release.md
Primary installer artifacts in this starter:
- macOS: signed/notarized DMG when secrets are configured, otherwise an unsigned DMG
- Windows: NSIS
.exeinstaller, optionally signed - Linux: AppImage output remains available, but Linux signing and verification are still out of scope for this slice
GitHub Actions packaging also writes one SHA-256 manifest per platform artifact set:
- macOS:
desktop-django-starter-macos-sha256.txtfor the DMG artifact upload - Windows:
desktop-django-starter-windows-sha256.txtfor the NSIS.exeartifact upload - Linux:
desktop-django-starter-linux-sha256.txtfor the AppImage artifact upload
Those checksum files are uploaded as separate workflow artifacts so an admin can verify the downloaded installer before promoting it into a connected release channel or transferring it through an offline/manual flow.
Manual update model for this repo:
- connected installs: download the installer plus its matching SHA-256 file from GitHub Actions artifacts, a GitHub Release, or your internal release channel, verify the checksum, then run the installer manually
- air-gapped installs: transfer the DMG or
.exeplus its matching SHA-256 file through the approved offline channel, verify version and integrity, then run the installer manually - local writable state survives reinstall/update because packaged mode keeps it under Electron's per-user app-data directory, with the SQLite database stored as
app.sqlite3
Staged Bundled Runtime Contract
The staged packaged-backend layout is now explicit enough to mirror a later packaged app:
electron/.stage/backend/manage.py: Django entrypoint kept at backend rootelectron/.stage/backend/src/: app source treeelectron/.stage/backend/python/: bundled Python runtime plus installed dependencieselectron/.stage/backend/staticfiles/: collected static assets forDEBUG=Falseelectron/.stage/backend/runtime-manifest.json: runtime metadata that records the staged interpreter and launcher contract
Electron packaged mode reads runtime-manifest.json to locate the bundled interpreter, then invokes manage.py from the backend root. The current staged manifest records the interpreter as python/bin/python3.12 on POSIX and is designed to allow python.exe on Windows.
The experimental Tauri bundle now uses that same staged contract by copying electron/.stage/backend/ into the app's packaged resources as backend/.
Electron now supervises two backend commands from that staged bundle:
manage.py runserver ...for the local web appmanage.py db_worker --queue-name default ...for the/tasks/demo worker
Dependencies are installed into the staged runtime under backend/python/lib/python3.12/site-packages on the current macOS/Linux path. On Windows, the same contract is expected to resolve inside the staged python/ tree rather than the repo environment.
Packaged mode still sets a small runtime environment at launch time:
DJANGO_SETTINGS_MODULE=desktop_django_starter.settings.packagedDESKTOP_DJANGO_APP_DATA_DIRfor writable SQLite/app dataDESKTOP_DJANGO_BUNDLE_DIRfor bundle-relative assetsDESKTOP_DJANGO_HOSTandDESKTOP_DJANGO_PORTfor localhost startupDJANGO_SECRET_KEYif one is not already suppliedPYTHONUNBUFFERED=1
What This Repo Should Eventually Provide
- A minimal Electron shell that starts Django locally
- A bundled Python runtime for packaged builds
- A tiny example Django app that still feels real
- Clear extension points for replacing the example with your own Django project
- Cross-platform packaging guidance with Windows as a required proof point
- Plain GitHub Actions packaging and artifact download flow for macOS, Windows, and Linux, including env-driven signing/notarization scaffolding
Production Gaps
- No auto-update feed, update server, or in-app updater is included.
- No GitHub Release publishing automation is wired yet; checksum generation exists, but promotion remains manual.
- Linux packaging still exists, but Linux signing and verification are not a baseline in this slice.
- Windows public-distribution hardening beyond optional signing inputs is still follow-on work.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file desktop_django_starter-0.1.0.tar.gz.
File metadata
- Download URL: desktop_django_starter-0.1.0.tar.gz
- Upload date:
- Size: 385.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.5 {"installer":{"name":"uv","version":"0.11.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e3721cde285afc28bfef6a9a8f67f6b07c3496c2d252527d58bac0465a3e692
|
|
| MD5 |
074b9df7687edb2fc5bf1e903f662ce0
|
|
| BLAKE2b-256 |
48cfd2ed5bd529b355ffdfc326cba6e0d6b5ed32724972e3c902fd33d800fae0
|
File details
Details for the file desktop_django_starter-0.1.0-py3-none-any.whl.
File metadata
- Download URL: desktop_django_starter-0.1.0-py3-none-any.whl
- Upload date:
- Size: 29.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.5 {"installer":{"name":"uv","version":"0.11.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d55dbcfac529a4128af0114ce73cfa06f4fda4b42258e22f7d1d7ab110f91d7
|
|
| MD5 |
d5abd00b6b53a18e108657461c091f52
|
|
| BLAKE2b-256 |
3a1c9b03b8fdcd4c5cf2d79c6c25c964e53961083443a6987bfd55e858c27535
|