Home Features Docs Blog Philosophy Examples FAQ
v0.9.0 — the 1.0 prep release

Django, live.
Production-ready.

Build reactive, real-time applications with Django and Python. djust 0.9 hardens the path to 1.0: Rust VDOM performance, resilient WebSocket recovery, progressive enhancement, and a smaller surface area for teams that want to ship without a JavaScript app.

Install Package
$ pip install djust
The release before 1.0

0.9 is the hardening release.

djust is moving from fast iteration to a stable 1.0 contract. The marketing story is simple: keep Django as the application model, use Rust where performance matters, and remove the frontend app unless you actually need one.

  • Framework package consolidation is complete: auth, tenants, theming, components, and admin now live behind core extras.
  • Rust partial rendering, keyed loops, temporary assigns, streaming, server actions, and markdown streaming are in the release line.
  • The remaining 1.0 work is intentionally boring: accessibility, progressive enhancement, recovery polish, docs, and migration sharp edges.
0.9.0
1.0 prep release

The stabilization release before djust 1.0: fewer footguns, clearer APIs, stronger docs.

Rust VDOM
Sub-ms patch engine

Server-render Django templates, then let Rust diff and patch only what changed.

0 JS app
Django-native DX

No frontend build pipeline, duplicated model types, or API layer just to make a form interactive.

Redis-ready
Horizontal scale

Production state backends, reconnect recovery, and HTTP fallback for real deployments.

Philosophy

Complexity is the enemy.

djust exists for teams that want interactive software without splitting their product into two applications. Keep the domain model, forms, validation, permissions, and rendering in Django. Use Rust for the VDOM hot path. Add JavaScript only when it earns its keep.

The goal for 1.0 is not novelty. It is a smaller, boringly reliable contract for server-rendered apps: fewer moving pieces, fewer duplicated types, fewer client/server seams, and a path from static HTML to real-time collaboration that still feels like Django.

Read the full philosophy
One application model

No mandatory API layer, frontend store, schema duplication, or build pipeline just to make ordinary product workflows feel live.

Progressive by default

Start with Django templates. Layer in events, streaming, presence, optimistic updates, and server push where the interaction actually needs them.

Performance without ceremony

Rust handles diffing and patch generation so Python can stay focused on the product logic your team already understands.

State Management Primitives

Complex client-side behavior, declared in Python. djust provides a suite of decorators that handle the hard parts of frontend development for you.

@debounce

Delay server requests until the user stops typing. Perfect for search inputs.

@debounce(wait=0.5)
def search(self, query):
  self.results = ...
@optimistic

Update the UI instantly, validate on the server later. Zero latency feel.

@optimistic
def like(self):
  self.liked = True
@cache

Cache responses client-side. Instant results for repeated queries.

@cache(ttl=300)
def get_cities(self):
  return Cities.all()
@client_state

Sync multiple components instantly without a server roundtrip.

@client_state(keys=['tab'])
def switch_tab(self, tab):
  self.tab = tab
shadcn/ui for Django

Copy. Paste. Own.

Stop fighting with npm packages. djust uses a component-as-code philosophy. Copy our components into your project and customize them to your heart's content.

  • Framework Agnostic Switch between Bootstrap 5 and Tailwind CSS with a single config setting.
  • Two-Tier Architecture Use lightweight Component for static UI and powerful LiveComponent for interactive widgets.
Browse Component Library
components/navbar.py
class Navbar(Component):
    def render(self):
        framework = config.get('css_framework')

        if framework == 'bootstrap5':
        elif framework == 'tailwind':
            return self._render_tailwind()

        return self._render_plain()
Performance Magic

The End of N+1 Queries.

The #1 performance killer in Django apps is the N+1 query problem. djust solves it automatically.

Our compiler analyzes your templates to see exactly which fields you use (e.g., {{ book.author.name }}). It then automatically injects the optimal select_related calls into your QuerySet.

See How It Works
Without djust
With djust
Template:
{% for book in books %}
  {{ book.author.name }}
{% endfor %}
SQL Queries:
SELECT * FROM books
SELECT * FROM authors WHERE id=1
SELECT * FROM authors WHERE id=2
... (100 more)
Template:
{% for book in books %}
  {{ book.author.name }}
{% endfor %}
SQL Queries:
SELECT * FROM books
JOIN authors ON ...
// 1 Query Total
Real-Time Built In

Everything Real-Time. Out of the Box.

Streaming, presence, server push, and data binding — all built into the framework with zero configuration.

Streaming

Stream LLM tokens, logs, or any async data directly to the browser.

self.stream_text("output", token)
Presence

Track who is online with automatic join/leave detection.

self.track_presence(user)
Server Push

Push updates from background tasks to connected clients.

push_to_view(view_id, data)
Data Binding

Two-way form binding with zero event handlers.

<input dj-model="name">
Multi-User Apps

Real-time Collaboration.
Three Lines of Python.

Presence tracking, live cursors, and broadcast updates — without WebSocket boilerplate, pub/sub clients, or frontend state machines.

Track who's online
# Mix in one class — that's it
class DocView(LiveView, PresenceMixin):
  presence_key = "doc:{doc_id}"

  def mount(self, request, **kwargs):
    self.track_presence(
      meta={"name": request.user.username}
    )

  def handle_presence_join(self, presence):
    # fires on every tab/device — auto-deduped
    self.viewers = self.list_presences()
Broadcast to everyone → all viewers
# One call pushes to every connected client
def save_document(self):
  self.doc.save()
  self.broadcast_to_presence(
    "doc_updated",
    {"saved_by": self.request.user.username},
  )
Live cursors LiveCursorMixin
# Swap PresenceMixin → LiveCursorMixin
class DocView(LiveView, LiveCursorMixin):
  ...

  def get_context_data(self, **kwargs):
    ctx = super().get_context_data(**kwargs)
    ctx["cursors"] = self.get_cursors()
    return ctx
Live in this document
A
B
C
+2
5 viewers · 3 editing
alice editing section 2
bob viewing
carol editing section 4
vs Phoenix Presence
Same mental model

join/leave hooks, metadata, group keys — directly inspired by Phoenix Presence.

No separate frontend state

Phoenix requires JS to merge presence diffs client-side. djust handles it server-side — your template just renders presences.

Works with any backend

Memory backend for dev, Redis for prod. Swap with one settings change.

Read the Presence docs