Home Features Docs Blog Philosophy Examples FAQ
0.9 architecture tour

The 1.0 foundation is already here.

Explore the Rust VDOM, Django-template compatibility, streaming primitives, and recovery work that make djust 0.9 the stabilization release before 1.0.

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)

Django Template 25.0ms
Jinja2 12.0ms
djust (Rust) 0.8ms
* Benchmarks on Apple M1 Pro. Includes parsing, diffing, and patch generation.
templates/dashboard.html
{% 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:

  1. Parser resolves {% extends %} and merges blocks.
  2. Merged template is compiled to Rust VDOM.
  3. State changes trigger a diff of the entire tree.
  4. Patches are sent for any changed node, anywhere in the tree.
Full Django template compatibility deep dive

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 fetched from the DB.
Deep dive: ORM JIT pipeline, Rust-speed serialization
Without djust
With djust ORM JIT
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
SELECT * FROM authors WHERE id=3
... (100 more)
Template:
{% for book in books %}
  {{ book.author.name }}
{% endfor %}
SQL Queries:
SELECT * FROM books
JOIN authors ON ...
// 1 Query Total

04. Python-First State Management

Complex UI patterns usually require JavaScript. djust provides Python decorators that handle them for you.

@debounce(wait=0.5)

Search & Autocomplete

Automatically delays the server request until the user stops typing. No more flooding your database with partial queries.

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

Instant Feedback

Updates the UI immediately in the browser, then validates on the server. If the server rejects it, the UI rolls back automatically.

@optimistic
def toggle_like(self):
  self.liked = not self.liked
@client_state

Component Sync

Synchronize state between multiple components purely on the client-side, without a server roundtrip.

@client_state(['tab'])
def set_tab(self, tab):
  self.tab = tab

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_handler allowlist, 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.
views.py
from djust import LiveView
from djust.streaming import StreamingMixin

class ChatView(StreamingMixin, LiveView):
    template_name = 'chat.html'

    async def ask_ai(self, prompt):
        self.stream_start('response')
        async for token in llm.stream(prompt):
            self.stream_text('response', token)
        self.stream_done('response')
views.py
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 LiveCursorMixin broadcasts 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.
tasks.py
from djust import push_to_view

# From a Celery task
@app.task
def process_upload(view_id, file_id):
    result = heavy_processing(file_id)
    push_to_view(view_id, {
        'progress': 100,
        'result': result,
    })
template.html
<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, reconnected callbacks for DOM elements.
  • Push Events Hooks can push events back to the server and receive events from it via pushEvent() and handleEvent().

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-model binds form inputs to server state. Changes propagate instantly without writing event handlers.
  • Smart Modifiers Use .lazy for on-blur updates or .debounce-300 for throttled typing — one attribute, zero boilerplate.
template.html
<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>