Quick Start Guide
From git clone to a running real-time app in under 2 minutes. No JavaScript required.
Clone the starter
djust-start is a minimal, opinionated djust project — everything wired up so you go from git clone to a running app with a live counter on :8000 in under 2 minutes.
# Clone the starter and step in
git clone https://github.com/djust-org/djust-start.git myapp
cd myapp
# Install dependencies and start the dev server
make install
make devThe server comes up on http://localhost:8000 with a working live counter — click the buttons and watch it update in real time, no full page reload.
Prefer to set it up manually?
Wire djust into a Django project from scratch — the same end result as the starter, step by step. Reach for this when you're adding djust to an existing app.
Prerequisites
python --versionInstall djust
Install djust via pip. This will also install Django and other dependencies.
# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install djust
pip install djustCreate a Django Project
Create a new Django project or use an existing one.
# Create new Django project
django-admin startproject myproject
cd myproject
# Create an app
python manage.py startapp counterConfigure Django Settings
Add djust and Channels to your INSTALLED_APPS in settings.py
# myproject/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'channels', # Required for WebSocket
'djust', # djust framework
'counter', # Your app
]
# Required: point Django at your ASGI application
ASGI_APPLICATION = 'myproject.asgi.application'
# Channel layer (in-memory for development)
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels.layers.InMemoryChannelLayer'
}
}Setup ASGI Routing
Configure WebSocket routing in asgi.py
# myproject/routing.py
from django.urls import path
from djust.websocket import LiveViewConsumer
websocket_urlpatterns = [
path('ws/live/', LiveViewConsumer.as_asgi()),
]
# myproject/asgi.py
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import myproject.routing
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(myproject.routing.websocket_urlpatterns)
),
})Create Your First LiveView
Create a simple counter with real-time updates in counter/views.py
# counter/views.py
from djust import LiveView
from djust.decorators import event_handler
class CounterView(LiveView):
template_name = 'counter/counter.html'
def mount(self, request, **kwargs):
self.count = 0
def get_context_data(self, **kwargs):
return {'count': self.count}
@event_handler()
def increment(self, **kwargs):
self.count += 1
@event_handler()
def decrement(self, **kwargs):
self.count -= 1
@event_handler()
def reset(self, **kwargs):
self.count = 0Create the Template
Create counter/templates/counter/counter.html
<!-- counter/templates/counter/counter.html -->
{% load djust_tags %}
<!DOCTYPE html>
<html>
<head>
<title>Counter Example</title>
{% djust_scripts %}
</head>
<body dj-view="{{ dj_view_id }}">
<div dj-root style="text-align: center; padding: 2rem;">
<h1>Counter: {{ count }}</h1>
<button dj-click="decrement">-</button>
<button dj-click="reset">Reset</button>
<button dj-click="increment">+</button>
</div>
</body>
</html>dj-view on <body> establishes the WebSocket connection. dj-root marks the reactive region that gets patched on updates. Both are required. Configure URLs
Add the URL pattern to myproject/urls.py
# myproject/urls.py
from django.contrib import admin
from django.urls import path
from counter.views import CounterView
urlpatterns = [
path('admin/', admin.site.urls),
path('', CounterView.as_view(), name='counter'),
]Run the Development Server
Start the server and see your counter in action!
uvicorn myproject.asgi:application --reloaduvicorn (or daphne), not manage.py runserver — the standard Django dev server is WSGI-only and does not support WebSockets. How It Works
count = 0 and sends full HTML to the browser. {"event": "increment"}self.increment(), updating self.count = 1[{path: [2,0], text: "1"}] and updates only the counter number. No full page reload! Directive Quick Reference
Browse all directives Now that your first view works, here's the dj-* vocabulary you'll reach for next.
dj-click dj-submit dj-change dj-input dj-blur dj-focus dj-keydown dj-keyup dj-poll dj-copy dj-confirm dj-model dj-mounted dj-shortcut dj-click-away
dj-patch # swap dj-root dj-navigate # SPA nav + history dj-prefetch # warm cache on hover
dj-window-keydown dj-window-scroll # 150ms throttle dj-window-resize # 150ms throttle dj-window-click dj-document-keydown dj-document-click
dj-debounce="300" # ms dj-debounce="blur" # until blur dj-throttle="500" # ms
dj-loading # toggle class dj-loading.hide # hide dj-loading.show # spinner dj-loading.disable # disable dj-disable-with="…" dj-lock
dj-cloak # hide til live dj-scroll-into-view .dj-connected # body class .dj-disconnected # body class
Next Steps
Explore Examples
See more complex examples like forms, todo lists, and data tables.
Read the Docs
Deep dive into components, forms, state management, and more.
Read the Blog
Tutorials, updates, and best practices for building with djust.
Star on GitHub
Check out the source code, report issues, and contribute.
Need Help?
Stuck on something? Check out the full documentation or browse working examples.