Home Features Philosophy Docs Blog Security Examples FAQ
v0.4.1 Released

Client-Side Behavior.
Server-Side Code.

Build reactive, real-time applications with Django and Python. No JavaScript required. Powered by a high-performance Rust VDOM engine.

Install Package
$ pip install djust

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