Knowledge base

Frequently asked questions

Answers about building with djust. Can't find yours? Ask in the community.

36 questions

Getting started

What is djust?

djust brings Phoenix LiveView-style reactive views to Django. You write server-side Python, and the browser updates itself over a WebSocket. On each event djust re-renders the view on the server, diffs it against the previous render in Rust, and sends only the changed patches.

There is no JavaScript to write, no bundler and no build step in your project. The ~61 KB gzipped client runtime is injected automatically.

Which Python and Django versions are supported?

djust 1.2 requires Python 3.10 or newer and supports Python 3.10 through 3.14. It supports Django 4.2, 5.0, 5.1 and 5.2. Django and Channels are installed as dependencies of djust.

How do I install djust and start a project?

The fastest start is the scaffold: run uvx djust@latest new myproject (or pip install djust and then djust new myproject), then cd myproject and make dev. It creates the project and a virtualenv, installs requirements, runs migrations and gives you a working starter page. Pass --bare for a minimal placeholder page.

To add djust to an existing project instead, add channels and djust to INSTALLED_APPS, configure a channel layer and route WebSockets in asgi.py.

Do I need to know Rust?

No. The whole API is Python. Rust is used internally for the template engine, the VDOM diff and serialization. Published wheels ship the compiled Rust core, so on supported platforms pip install djust needs no Rust toolchain. You only need Rust to build djust from source.

Do I need to write JavaScript?

Usually not. Events, forms, loading states, navigation and live updates are handled by dj-* template attributes and Python event handlers.

When you do need the browser, for a chart library, a map or a rich editor, dj-hook is the escape hatch. It attaches a small JavaScript object to an element, and that object can send events to the server and receive events back.

Can I use djust in an existing Django project?

Yes. LiveViews sit alongside ordinary Django views, so you can adopt djust one page at a time. Your models, forms, auth, permissions and middleware keep working.

Django REST Framework also keeps working. For pages built with djust you generally don't need a JSON API, because the logic runs on the server. Keep DRF for mobile apps and third-party integrations.

Can I use the Rust template engine without LiveView?

Yes. Point a TEMPLATES entry at djust.template_backend.DjustTemplateBackend and your existing TemplateViews, render() calls and includes render through Rust, with no WebSocket and no client runtime. Keep Django's own backend as a second entry for admin and contrib templates.

98.57% of Django's own template_tests suite passes unmodified against this backend (1032 of 1,047 cells). djust new configures it for you.

Can I use Tailwind or Bootstrap?

Yes, and any other CSS. djust has no opinion about your own markup. The css_framework key in LIVEVIEW_CONFIG ('bootstrap5' by default, or 'bootstrap4', 'tailwind', or None for plain HTML) only controls the classes djust puts on the form fields and components it renders for you. python manage.py djust_setup_css tailwind sets up a Tailwind build.

How it works

Where does LiveView state live?

Your state is ordinary Python attributes on the LiveView instance, which lives in the server process for as long as the page's WebSocket is open. The Rust side holds the compiled template and the last rendered VDOM, which is the baseline for the next diff.

That Rust view is cached in a state backend, in memory or in Redis, serialized with MessagePack. Large Redis entries are zstd-compressed when zstandard is installed. Patches go to the browser as JSON.

How many server-side instances does each user create?

One LiveView instance for each open page, held for as long as its WebSocket connection lasts. Ten users on a page means about ten instances. Components run inside their parent LiveView on the same connection, so they don't open connections of their own. Memory per instance is roughly the size of the state you keep on it, which is a good reason to keep large querysets out of it.

When is state cleaned up?

The LiveView instance is dropped when its WebSocket closes. The cached view in the state backend expires after SESSION_TTL seconds (3600 by default, set in DJUST_CONFIG). Redis expires entries on its own. With the in-memory backend, run python manage.py cleanup_liveview_sessions periodically. The in-memory backend is thread-safe but is meant for development and single-process deployments.

Do I need WebSockets?

WebSockets are the default and give the lowest latency. If they're blocked in your environment, set LIVEVIEW_CONFIG = {'use_websocket': False} and mount djust.sse.sse_urlpatterns. The client then receives updates over a Server-Sent Events stream and sends each event as an HTTP POST. It isn't polling, so server push still works. Expect more latency and server load than with WebSockets.

What are the tradeoffs compared with an SPA?

Server memory grows with concurrent users, because each open page holds a LiveView instance. Every interaction makes a round trip to the server, so it can never be as instant as purely client-side code. The ecosystem is younger, with fewer third-party components than React or Vue.

In return, forms, CRUD screens, dashboards and real-time updates need one Python codebase, with no API layer and no frontend build.

What apps are not a good fit for djust?

UIs that need instant feedback on every frame, such as games, drawing tools or heavy drag-and-drop, are a poor fit because each interaction goes to the server. So are offline-first apps. djust has PWA helpers, but a LiveView needs a live server connection to respond to events. For those parts of an app, use a client-side library, and mount it inside a djust page with a hook if you like.

Features

What does djust do for security?

Built in: CSRF protection, automatic escaping in the Rust template engine, a WebSocket Origin check against ALLOWED_HOSTS, per-connection rate limiting, and view- and handler-level permissions. Only methods marked @event_handler are callable from the browser. manage.py djust_audit reports each view's auth posture, and the djust.S005 system check flags state exposed without authentication.

Advisories are published on GitHub's Security tab. Report vulnerabilities privately to security@djust.org.

How does dj-model two-way binding work?

Add dj-model="field_name" to an input, and each change sets that attribute on your view, with type coercion and without an event handler. dj-model.lazy syncs on blur, and dj-model.debounce-300 waits 300 ms.

The sync doesn't re-render the page, so the input you're typing in isn't disturbed. For live search or validation as you type, use dj-input="handler" or dj-change="handler" instead.

What are dj-hook JavaScript hooks?

Register an object on window.djust.hooks and attach it with dj-hook="Name". djust calls its mounted, beforeUpdate, updated, destroyed, disconnected and reconnected callbacks. Inside, this.el is the element, this.pushEvent(event, payload) sends an event to the server, and this.handleEvent(name, callback) receives events the server pushes. Use hooks to integrate chart, map and editor libraries.

How does LLM streaming work?

Streaming is built into LiveView, so you don't add a mixin. In an async event handler, call stream_text() to append tokens to an element marked dj-stream="name", or stream_to() to re-render one part of the template. Finish with stream_done() (or stream_error()). Updates are throttled to about 60 per second and travel over the page's existing connection, so no extra SSE endpoint is needed.

How does presence tracking work?

Add PresenceMixin to a view and call track_presence(), and list_presences() returns who is on the page. The mixin maintains online_count, and you can override handle_presence_join() and handle_presence_leave() to react to users arriving and leaving. LiveCursorMixin adds live cursors. For more than one server, set DJUST_CONFIG['PRESENCE_BACKEND'] = 'redis'.

What is push_to_view and when should I use it?

push_to_view("myapp.views.DashboardView", state={...}) updates every client connected to that view from outside a request: a Celery task, a management command, a signal or a webhook. You can also pass handler= and payload= to run a handler on each instance. Use apush_to_view() from async code. It uses Django Channels groups, so across processes it needs a shared channel layer such as Redis.

Can I build a multi-tenant SaaS with djust?

Yes, with row-level tenancy. TenantMixin resolves the tenant from the subdomain, path, header, session or a custom resolver and sets self.tenant. TenantScopedMixin adds get_tenant_queryset(), get_tenant_object() and create_for_tenant(). It doesn't filter querysets automatically, so go through those helpers. Presence is scoped per tenant. Schema-per-tenant through django-tenants is deprecated under djust.

Does djust support progressive web apps?

Yes. With {% load djust_pwa %}, the djust_pwa_head tag adds the manifest and meta tags, and djust_sw_register registers a service worker that caches pages and static assets. PWAMixin, OfflineMixin and SyncMixin add an offline queue that syncs through your own handlers. djust is still a server-driven framework, and events need a live connection to reach your views.

Performance & scaling

How fast is djust?

In the repository's benchmark (benchmarks/benchmark.py), the Rust engine renders a 10,000-row filtered list 11.2x faster than Django's engine and a simple list 7.1x faster. Static markup is the same speed, because there is nothing to accelerate. On updates, djust sends a diff of what changed rather than the whole page. You can reproduce the numbers with make build && python benchmarks/benchmark.py.

How many concurrent users can one server handle?

We don't publish a connections-per-server figure, because it depends mostly on your app: how much state each view holds and how much work each handler does. Each open page costs one LiveView instance plus its connection. WebSocket compression adds about 64 KB per connection. The deployment guide has sizing tiers, and Redis-backed state lets you add servers.

Can I defer loading below-the-fold LiveViews?

Yes. Add dj-lazy to an element that has dj-view, and djust delays mounting that LiveView until the element scrolls into view. dj-lazy="click" and dj-lazy="hover" mount it on first interaction instead. That saves server memory on pages that embed several LiveViews.

Deployment

How do I deploy djust to production?

Deploy it like any Django app, but run an ASGI server rather than WSGI: uvicorn myproject.asgi:application, or Gunicorn with Uvicorn workers in containers. In front of it, your proxy must pass WebSocket upgrades. For more than one process, use Redis for the state backend and for the Channels layer.

Is there managed hosting for djust apps?

Yes. djustlive.com is the managed hosting platform for djust applications, and the deploy CLI ships with djust. Run djust deploy login to sign in through your browser, then djust deploy from your project directory to upload and deploy it. djust deploy status shows how it went.

How do I scale across several servers?

Set DJUST_CONFIG = {'STATE_BACKEND': 'redis', 'REDIS_URL': ...} (install djust[redis]) so any server can restore a view when a client reconnects. Separately, set CHANNEL_LAYERS to channels_redis so push_to_view, presence and notifications cross processes. Pin each WebSocket to one server with sticky routing, such as nginx ip_hash or ALB cookie stickiness. If that server goes away, the client reconnects elsewhere and its state comes from Redis.

My WebSocket keeps disconnecting. What's wrong?

Usually it's the proxy. In nginx, set proxy_http_version 1.1, pass the Upgrade and Connection headers, and raise proxy_read_timeout, whose default closes idle sockets after 60 seconds. Also check that the page's host is in ALLOWED_HOSTS, because the Origin check closes the socket with code 4403 otherwise. djust reconnects automatically with backoff and restores form values.

Comparisons

How is djust different from Phoenix LiveView?

djust takes LiveView's model, server-held state with events up and diffs down, and brings it to Django. You write Python rather than Elixir, and you keep Django's ORM, forms, auth and admin. Templates are Django templates, rendered and diffed by a Rust engine. If your team and code are already on Django, djust saves you a rewrite. If you're already on Elixir, Phoenix is the natural choice.

How does djust compare to Laravel Livewire?

They solve the same problem for different stacks: Livewire for Laravel and PHP, djust for Django and Python. The developer experience is similar. The main architectural difference is transport: Livewire sends each interaction as an HTTP request, while djust keeps a WebSocket open by default, so the server can push updates without the client asking.

Should I use djust or HTMX?

HTMX is stateless and framework-agnostic: you write endpoints that return HTML fragments and wire each swap by hand. djust keeps state on the server between events, works out the DOM changes by diffing, pushes updates over a WebSocket, and integrates with Django forms. Choose HTMX for lightly interactive pages. Choose djust when a page has real state, like multi-step forms, dashboards, live data or streaming.

Project & community

Is djust free?

Yes. djust is open source under the MIT license, including for commercial use. Managed hosting on djustlive is a separate, optional service.

How stable is the API, and how do I upgrade?

Since 1.0.0 djust follows Semantic Versioning. Code written against the public API keeps working across every 1.x release, and deprecated APIs survive until at least the next major release. Underscore-prefixed names are internal. Read the release notes before upgrading. djust new, the development server and manage.py check tell you when a newer release or a security advisory affects your version.

Does djust work well with AI coding agents?

It's designed to. djust new writes an AGENTS.md that points agents at the engineering conventions and the focused AI reference in the repository's docs/ai/ directory. djust also ships an MCP server (manage.py djust_mcp) that lets an assistant query the real directives, decorators and your project's views, so it doesn't have to guess.

Where can I get help?

Start with the documentation at docs.djust.org. For questions, use the djust.org community forum, the Discord server, or GitHub Discussions. Report bugs as GitHub issues. For anything else, email support@djust.org. Security reports go privately to security@djust.org, not to a public issue.

Still have a question?