# Django LiveView vs Phoenix LiveView: a real benchmark A reproducible, Docker-based benchmark comparing **django-liveview** (WebSocket + Django Channels + Stimulus) against **Phoenix LiveView** (WebSocket + BEAM + LiveView diffs). Both apps implement an identical alert dashboard: add, delete, and search alerts in real time. The benchmark is fully automated with Playwright headless Chromium. --- ## Stack versions | Component | Django LiveView | Phoenix LiveView | | --- | --- | --- | | Language | Python 3.12 | Elixir 1.17.3 / OTP 27 | | Framework | Django 6.0.5 | Phoenix 1.7 | | LiveView lib | django-liveview 2.2.0 | phoenix_live_view 1.0 | | WS layer | Channels 4.3.2 + channels-redis 4.3.0 | Built-in (BEAM) | | HTTP server | Uvicorn 0.47.0 | Bandit 1.5 | | Database | PostgreSQL 16 | PostgreSQL 16 | | Cache/broker | Redis 7 | — | --- ## How each framework works | | Django LiveView | Phoenix LiveView | | --- | --- | --- | | Transport | WebSocket (Django Channels) | WebSocket (BEAM) | | Updates | Explicit HTML snippets per selector | Automatic template diffs | | State | Stateless (DB per action) | In-memory assigns + DB for mutations | | JS | liveview.js (Stimulus + WS client) | phoenix_live_view.js | | Server | Uvicorn (ASGI) | Bandit (HTTP/WS) | --- ## Scenarios ### Common (10 iterations, 2 warmup) | # | Scenario | What it measures | | --- | --- | --- | | 1 | **Add alert** | Click → new row appears (append) | | 2 | **Delete alert** | Click → row disappears | | 3 | **Search / filter** | Input → filtered list rendered | ### Edge cases (5 iterations, 1 warmup) | # | Scenario | What it measures | | --- | --- | --- | | 4 | **Add to large list** | Add one alert with 500 already loaded | | 5 | **Rapid fire** | 5 consecutive clicks (50 ms apart) → all 5 rows appear | | 6 | **Empty search** | Search for non-existent term → empty state | --- ## Results Full results, charts, and analysis are available in the article: [Django LiveView vs Phoenix LiveView: a real benchmark](https://en.andros.dev/blog/80134668/django-liveview-vs-phoenix-liveview-a-real-benchmark/) --- ## How to run ### 1. Start the apps ```bash docker compose up --build -d django phoenix ``` Wait until both are healthy (check `docker compose ps`). ### 2. Run the benchmark ```bash docker compose --profile bench run --rm benchmark ``` Results land in `./results/` as: - `results_.csv` — raw per-iteration data - `report_.md` — summary tables (replace the placeholders above) ### 3. Manual exploration | App | URL | | --- | --- | | Django LiveView | http://localhost:8001 | | Phoenix LiveView | http://localhost:8002 | --- ## Benchmark methodology - **Timing**: wall-clock `time.perf_counter()` from DOM action to DOM mutation detected by Playwright. - **WS payload**: Playwright `framesent` / `framereceived` events summed per interaction. - **Warmup**: first N iterations discarded (default 2 for common, 1 for edge cases). - **DB state**: cleared via HTTP `/bench/clear/` before each scenario; pre-populated via `/bench/populate/?count=N` where needed. - **WS ready**: benchmark waits for `#ws-status` to read `"connected"` before starting. - **Browser**: headless Chromium via Playwright. --- ## Related work - [django-interactive-frameworks-benchmark](https://github.com/tanrax/django-interactive-frameworks-benchmark) — previous benchmark comparing multiple Django interactive frameworks. - [django-liveview](https://github.com/tanrax/django-liveview) — the Django LiveView package used here.