A stable foundation ships today.
Explore the Rust VDOM, Django-template compatibility, streaming primitives, and recovery work hardened across the djust 1.x releases — a stable foundation for real-time Django applications.
What are you trying to build?
Start with the problem you need to solve, then jump into the implementation detail when you’re ready.
Keep updates small
Use Rust diffing and automatic query planning when full-page work starts to hurt.
Keep your templates
Add reactivity without replacing Django templates, forms, URLs, or domain logic.
Ship with guardrails
Keep security defaults, client escape hatches, and a deployment path in the same stack.
Make the page feel live
Stream work, show presence, and push server-side changes into connected browsers.
01. Rust VDOM Engine
Traditional Django templates re-render the entire string for every request. djust compiles templates into a Virtual DOM tree in Rust.
- Sub-millisecond Patching Rust handles the hot path: dependency-aware rendering, VDOM diffing, and compact patches for changed nodes.
- Smart Diffing We track variable dependencies. If you only change
{{ count }}, we only check that node.
Rendering Performance (100 items)
{% extends "base.html" %} {% block title %}Dashboard{% endblock %} {% block content %} <div class="stats"> <h1>Welcome, {{ user.name }}</h1> <!-- This updates independently --> <div>Active Users: {{ active_count }}</div> <!-- Loop updates are optimized --> {% for item in items %} <div>{{ item.name }}</div> {% endfor %} </div> {% endblock %}
02. Unified Templates
Don't learn a new syntax. djust supports standard Django template inheritance.
The entire page—base template, child template, and included components—is compiled into a single VDOM tree. This means you can update a variable in the navbar (defined in `base.html`) from a view rendering `child.html`.
How it works:
- Parser resolves
{% extends %}and merges blocks. - Merged template is compiled to Rust VDOM.
- State changes trigger a diff of the entire tree.
- Patches are sent for any changed node, anywhere in the tree.
03. ORM JIT Compiler
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 and prefetch_related calls into your QuerySet.
- Zero N+1 Queries Forgot
select_related? No problem. We fix it for you. - Zero Data Leaks If a field isn't in the HTML, it's never serialized to the client.
{% for book in books %} {{ book.author.name }} {% endfor %}
{% for book in books %} {{ book.author.name }} {% endfor %}
JOIN authors ON ...
04. Python-First State Management
Complex UI patterns usually require JavaScript. djust provides Python decorators that handle them for you.
Search & Autocomplete
Automatically delays the server request until the user stops typing. No more flooding your database with partial queries.
@event_handler @debounce(wait=0.5) def search(self, value: str = "", **kwargs): self.results = DB.search(value)
Scroll & Drag Events
Sends at most one event per interval, keeping the first and the last. High-frequency input stays responsive without flooding the server.
@event_handler @throttle(interval=0.1) def on_scroll(self, scroll_y: int = 0, **kwargs): self.scroll_y = scroll_y
Repeat Lookups
Caches handler responses in the browser for a TTL, keyed by the parameters you name. Repeating a query skips the server roundtrip.
@event_handler @cache(ttl=60, key_params=["query"]) def lookup(self, query: str = "", **kwargs): self.results = DB.search(query)
05. Security by Default
WebSocket-based frameworks open new attack surfaces. djust locks them down out of the box so you don't have to think about it.
- WebSocket Event Hardening Three-layer defense: event name guard,
@event_handlerallowlist, and server-side rate limiting. - Built-in Security Utilities
safe_setattr()blocks prototype pollution,sanitize_for_log()prevents log injection, DEBUG-aware error handling. - Per-IP Connection Limits Prevents resource exhaustion from a single client opening hundreds of WebSocket connections.
06. Real-Time Streaming
Stream data to the browser as it generates. Perfect for LLM responses, live logs, and progress indicators — no polling required.
- Token-by-Token Output Stream LLM responses, logs, or any async data directly to the browser as it generates.
- Multiple Stream Targets Use
stream_to()to push updates to different DOM elements simultaneously.
from djust import LiveView, event_handler class ChatView(LiveView): # StreamingMixin is built in template_name = 'chat.html' @event_handler() async def ask_ai(self, prompt: str = '', **kwargs): await self.stream_start('response') async for token in llm.stream(prompt): await self.stream_text('response', token) await self.stream_done('response')
from djust import LiveView, PresenceMixin class DocView(LiveView, PresenceMixin): presence_key = 'doc:{doc_id}' def mount(self, request, **kwargs): self.doc_id = kwargs['doc_id'] self.track_presence( meta={'name': request.user.username} ) def handle_presence_join(self, presence): self.viewers = self.list_presences() def handle_presence_leave(self, presence): self.viewers = self.list_presences()
07. Live Collaboration & Presence
Build collaborative features without third-party services. Know who's online, track cursors, and broadcast changes — all built in.
- Who's Online Built-in presence tracking shows connected users in real-time with automatic join/leave detection and heartbeat cleanup.
- Broadcast Updates
broadcast_to_presence(event, payload)pushes to every connected client in the presence group — no pub/sub client required. - Live Cursors
LiveCursorMixinbroadcasts cursor positions for Google Docs-style collaboration.
08. Server Push
Push updates from anywhere in your backend — Celery tasks, management commands, webhooks — directly to the browser without the user lifting a finger.
- Background to Browser Push state updates from Celery tasks, management commands, or any background process directly to connected clients.
- Async Support Use
apush_to_view()in async contexts for non-blocking push operations.
from djust import push_to_view # From a Celery task — first arg is the dotted view-class path @app.task def process_upload(file_id): result = heavy_processing(file_id) push_to_view('myapp.views.UploadView', state={ 'progress': 100, 'result': result, })
<div dj-hook="Chart"> <canvas id="myChart"></canvas> </div> <script> djust.hooks.Chart = { mounted() { this.chart = new Chart(this.el, data); }, updated() { this.chart.update(); } }; </script>
09. JavaScript Hooks
When you need client-side power, hooks give you full lifecycle control over DOM elements without leaving the djust ecosystem.
- Full Lifecycle Control
mounted,updated,destroyed,disconnected,reconnectedcallbacks for DOM elements. - Push Events Hooks can push events back to the server and receive events from it via
pushEvent()andhandleEvent().
10. Two-Way Data Binding
Bind form inputs to server state with a single attribute. No JavaScript event handlers, no manual serialization — just dj-model.
- Automatic Sync
dj-modelbinds form inputs to server state. Changes propagate instantly without writing event handlers. - Smart Modifiers Use
.lazyfor on-blur updates or.debounce-300for throttled typing — one attribute, zero boilerplate.
<form> <input dj-model="name" placeholder="Your name"> <textarea dj-model.lazy="bio"> </textarea> <input dj-model.debounce-300="search" placeholder="Search..."> <p>Hello, {{ name }}!</p> </form>
See it, build it, ship it.
Try the live interaction, build your first LiveView, then deploy the same Django app when it’s ready.