You don't need React to be reactive — djust 1.0 is here

If you've ever finished a clean Django backend, looked at the next ticket — "make this update live" — and felt your shoulders drop, this is the post for you. We've been building djust in semi-public since January 2026, and today it hits 1.0.
What djust is
djust brings the proven Phoenix LiveView model to Django: server-driven reactive UI in pure Python. We did not invent server-side reactivity — Elixir's Phoenix and Laravel's Livewire proved the pattern works at scale. What's new is the execution: a Rust VDOM and template engine on the hot path so rendering stays sub-millisecond, a zero build step, and a security model built for the AI era. That combination has never existed for Django before.
Concretely: you write views in Django. You write templates in Django's template language. Your buttons get a dj-click="some_method" attribute. That's it. When the user clicks, the framework calls some_method on the server, lets you mutate state, re-renders the template, diffs the result against the previous render, and sends only the changed bytes to the browser over WebSocket. The browser updates without re-rendering.
No client state. No JavaScript framework. No build step. The browser is a dumb renderer of bytes the server sends it. The server is the only place state lives. There is no "sync the React store with the API" problem because there is no React store and there is no API.
A complete reactive counter — view and template, inline — is this much code:
from djust import LiveView
from djust.decorators import event_handler
class Counter(LiveView):
template = """
<div>
<h1>{{ count }}</h1>
<button dj-click="increment">+1</button>
</div>
"""
def mount(self, request, **kwargs):
self.count = 0
@event_handler()
def increment(self):
self.count += 1
That's the whole counter. No useState, no setState, no JSX, no pnpm install, no webpack.config.js. The dj-click is one attribute the framework looks for. The handler is plain Python. The state lives on the server.
What you specifically don't have to do
This is the thing the existing pitch ("it's like React but faster") leaves out. djust isn't a faster React. It's the absence of half of what React is for:
- No client state. The server holds the source of truth. The browser receives bytes and renders them. When the server's view of the world changes, the framework figures out what's different and sends the patch.
- No build step. You don't need
node_modules. You don't need a bundler. You don't need a CI step that compiles your frontend. The framework's client runtime ships as one minified file (54 KB gzipped, ~45 KB brotli) that you load with a Django template tag. - No JSON API for your views. You don't write a serializer for the data your template needs. The template is the contract. If your template reads
{{ user.name }}, the framework knows to send that whenuser.namechanges. - No two-way data binding sync. Form inputs with
dj-change="some_handler"automatically debounce, validate, and update server state. When the WebSocket reconnects after a network blip, form values are restored without you writing recovery code. - No client-side router. Server-side URL changes work the way they always have in Django. djust composes with Turbo-style navigation if you want SPA-like feel, but you're not building an SPA.
- No separate test stack. Your views are Python classes; you test them the way you test Django views. There's a
LiveViewTestClientfor end-to-end driving, but nothing JS-test-stack-shaped is required.
If you've been hand-rolling Alpine.js, Stimulus, HTMX, or a sprinkle of jQuery to make Django feel responsive — and you've felt the duplication of having logic in two languages — this is for that exact moment.
The sweet spot: data-driven UI
If your next ticket is "make this form live-validate" or "make this dashboard update in real time," djust is built for you. Your handlers query the Django ORM directly; FormMixin validates against your models on every change; object permissions and model binding are first-class. It also works for chat, presence, and collaboration — anywhere the server holds the state — but data-driven CRUD, dashboards, and admin tools are the sweet spot.
The counter is the obligatory demo. Here's something closer to real code — a live-validating signup form, built on FormMixin:
from django import forms
from djust import LiveView
from djust.forms import FormMixin
class SignupForm(forms.Form):
email = forms.EmailField()
class SignupView(FormMixin, LiveView):
template_name = "signup.html"
form_class = SignupForm
def form_valid(self, form):
self.success = "You're in."
<!-- signup.html -->
<form dj-submit="submit_form">
{% csrf_token %}
<input type="email" name="email" value="{{ form_data.email }}"
dj-change="validate_field">
{% if field_errors.email %}<span>{{ field_errors.email.0 }}</span>{% endif %}
<button type="submit">Sign up</button>
</form>
The user types in the email field, the validation runs server-side against your real Django form, your real business logic, your real ORM — the error message appears under the field, without a page reload, without a single line of JavaScript that you wrote, all using the Django form classes and template syntax you already know.
One stack, one perimeter
One stack, one language, one deploy, one stack trace. No JSON API to design, no API schema to keep in sync, no frontend/backend split, no build step, no node_modules — that's the delivery-speed dividend.
It's also one auth perimeter: no second API auth surface, no client-trusted serialization, no CORS to misconfigure. The server stays canonical for state, and you secure handlers with the same Django tools you already use — login_required, @permission_required, object permissions. The WebSocket is that single perimeter, and it ships with origin validation, HMAC message signing, and per-view rate limiting. There are fewer places to get security wrong because there are fewer places where security has to be gotten right.
How it actually works — and why Rust
Briefly, because the implementation is more interesting than most "X but faster" frameworks let on:
- Python holds your view code, your event handlers, your state, your familiar Django integration.
- Rust holds the template engine, the virtual DOM, the diff, the wire-protocol serialization.
- They talk through PyO3. The Rust crate is statically
Send/Sync-checked, has nounwrap()in library code, and ships with no native deps beyond what Python itself already links. - On each event: handler runs in Python → state mutates → template re-renders in Rust → new VDOM is diffed against previous VDOM in Rust → resulting patches go over WebSocket → client runtime applies them to the DOM.
- WebSocket is the default transport. There's an HTTP-POST fallback for corporate proxies that block WebSocket and a Server-Sent Events fallback for environments that block both. Transport negotiation is automatic; the user never knows.
The Rust engine isn't an aesthetic choice — it's because the diff and the template engine are on the hot path. Putting Rust there keeps template rendering sub-millisecond, which you can't reliably do in pure Python (we tried). This is the same tradeoff Pydantic v2, ruff, and uv all made — a Python-facing API with a Rust core where the work is hottest — and the same answer.
Importantly: you never write Rust. It's invisible. It's a wheel that pip installs. There's no Rust toolchain in your CI. The pre-built wheels cover every supported platform.
Try it
Before you install anything, try it live at start.djust.org — a real djust app running in your browser. Click the reactions, vote in the poll, post to the guestbook, and watch it update for everyone on the page in real time. It's multi-user, it's server-driven, and there's nothing to install. The Python behind each interaction is shown right on the page.
Then, when you want your own:
pip install djust
Start here — a 5-minute counter walkthrough that ends in a working app.
🎮 start.djust.org — The live, multi-user playground above. Open it in two tabs and watch them sync. 📚 docs.djust.org — Getting started, guides, the full API reference, the accessibility guide, the architecture guide. 🌐 djust.org — Live playground, examples (counter, chat, dashboard, signup, multi-tenant), the manifesto, the comparison page. ⭐ github.com/djust-org/djust — Source. MIT-licensed. Issues welcome. 💬 Discord — Drop in, say what you're building, ask questions. Maintainers hang out here.
Thanks
To everyone who tried 0.x in production and filed real bugs — every one shaped the 1.0 surface. To Phoenix LiveView for showing what reactive server-side rendering could be. To HTMX for proving Python web devs were ready for an alternative to the React stack. To Django for being the framework worth building this on top of.
If you've been waiting for a reactive Python framework that doesn't force you out of Python — try djust. If you've been using HTMX or Unicorn and want to go further with the same mental model — try djust. If you're allergic to node_modules and want server-rendered reactivity in 54 KB of client — try djust.
pip install djust
It's 1.0. It's stable. It's pure Python on top, Rust under the hood, and zero JavaScript framework in between.
— The djust team
Related Posts

djust 0.4.0 — The Developer Experience Release
djust 0.4.0 ships 30+ features focused on developer experience: flash messages, keyboard shortcuts, form recovery, scaffolding generators, debug tooling, and security hardening. Build real-time Django apps with less code than ever.

djust 0.3.0 — "Phoenix Rising" 🔥
The biggest djust release yet with 20+ major features. Authentication, server-push, multi-tenancy, PWA support, AI tooling, automatic change tracking, CSS framework support, and security hardening make 0.3 production-ready.

djust 0.2.2: The Debug Panel Gets Real
djust 0.2.2 transforms the debug panel from a static inspector into a live development companion. Event filtering, replay, network inspection, VDOM patch tracing, and live state updates via WebSocket — all wired up and working out of the box.