Skip to content

StateZeroYour Django backend, supercharged

Build decoupled JavaScript SPAs with Django-Template like simplicity. Turn your Django backend into a live, reactive data source.

Your Django App + Decoupled JavaScript SPAs

You've built a solid Django backend. Now you want to add a modern, decoupled JavaScript SPA without rewriting everything.

The old way: Build REST APIs, manage state, handle WebSockets, debug sync issues for weeks.

StateZero way: Your Django models work directly in JavaScript SPAs. Build Vue.js frontends or vanilla JS applications with Django-like simplicity but delivering full modern SPA experiences.

See Your Django Models in Action

Check out our live demo to see Django models working in real-time with optimistic updates, live querysets, and file uploads.

The Problem Every Django Developer Faces

You have working Django models and want to build a modern decoupled SPA. You want the frontend to deploy separately, scale independently, and use modern JavaScript frameworks. But implementing real-time, reactive SPAs means:

python
# Your Django models work perfectly
class Task(models.Model):
    title = models.CharField(max_length=200)
    completed = models.BooleanField(default=False)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    
    def clean(self):
        if not self.title.strip():
            raise ValidationError("Title cannot be empty")
javascript
// But your frontend becomes a nightmare of boilerplate
const [tasks, setTasks] = useState([]);
const [loading, setLoading] = useState(true);

// Fetch data
useEffect(() => {
  fetch('/api/tasks/')
    .then(res => res.json())
    .then(data => {
      setTasks(data);
      setLoading(false);
    });
}, []);

// Optimistic updates (so UI feels snappy)
const toggleTask = async (taskId) => {
  // Update UI immediately
  setTasks(prev => prev.map(task => 
    task.id === taskId ? {...task, completed: !task.completed} : task
  ));
  
  try {
    await fetch(`/api/tasks/${taskId}/`, {
      method: 'PATCH',
      body: JSON.stringify({completed: !task.completed})
    });
  } catch (error) {
    // Revert on failure
    setTasks(prev => prev.map(task => 
      task.id === taskId ? {...task, completed: !task.completed} : task
    ));
  }
};

// Real-time updates (so everyone stays in sync)
useEffect(() => {
  const ws = new WebSocket('ws://localhost:8000/tasks/');
  ws.onmessage = (event) => {
    const {type, task} = JSON.parse(event.data);
    if (type === 'task_updated') {
      setTasks(prev => prev.map(t => t.id === task.id ? task : t));
    }
  };
  return () => ws.close();
}, []);

// Plus error handling, conflict resolution, connection state...

You wrote 50+ lines of complex code and haven't built a single feature yet.

The Solution: Django ORM Syntax in Decoupled JavaScript SPAs

python
# Your Django models stay exactly the same
class Task(models.Model):
    title = models.CharField(max_length=200)
    completed = models.BooleanField(default=False)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    
    def clean(self):
        if not self.title.strip():
            raise ValidationError("Title cannot be empty")
javascript
// Your decoupled Vue.js/vanilla JS SPA becomes this simple
import { useQueryset } from '@statezero/core/vue';
import { Task } from './models';

const tasks = useQueryset(() => Task.objects.filter({ user: currentUser.id }));

const toggleTask = (task) => {
  task.completed = !task.completed;
  task.save(); // Validates in Django, updates everywhere instantly
};

// That's it. You get:
// ✅ Optimistic updates - UI feels instant
// ✅ Real-time sync - Changes appear automatically  
// ✅ Django validation - Your clean() method runs
// ✅ Rich permissions - Field-level and object-level access control
// ✅ Decoupled deployment - Frontend and backend deploy independently
// ✅ Auto-optimized queries - StateZero handles select_related/prefetch_related

// 5 lines instead of 50+. Build your SPA features.

Your Django Backend Powers Everything

StateZero doesn't replace Django – it supercharges it. Your existing Django app becomes a live, reactive data source:

python
# Keep your existing Django models (zero changes)
class Order(models.Model):
    product_name = models.CharField(max_length=100)
    quantity = models.PositiveIntegerField()
    status = models.CharField(max_length=20, choices=STATUS_CHOICES)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)
    
    def clean(self):
        if self.quantity <= 0:
            raise ValidationError("Quantity must be positive")

# Keep your existing permissions
class OrderPermission(AbstractPermission):
    def filter_queryset(self, request, queryset):
        if request.user.is_staff:
            return queryset
        return queryset.filter(created_by=request.user)
    
    def allowed_actions(self, request, model):
        return {ActionType.READ, ActionType.CREATE}
    
    def visible_fields(self, request, model):
        return {"id", "product_name", "quantity", "status", "created_by"}
    
    def editable_fields(self, request, model):
        return {"product_name", "quantity"}
javascript
// Use them directly in your frontend - full Django ORM power
const myOrders = useQueryset(() => Order.objects.filter({ 
  created_by: currentUser.id,  // snake_case field names (like Django)
  status: 'pending'
}));

const createOrder = (productName, quantity) => {
  const order = Order.objects.create({
    product_name: productName,     // snake_case fields, camelCase methods
    quantity: quantity,
    created_by: currentUser.id
  });
  // Django validation runs automatically
  // Permission classes control access (field-level + object-level)
  // Other users see the change instantly
  // Queries are automatically optimized
};

// Your sophisticated permission system just works

Real-Time Collaboration, Zero Infrastructure

What users expect: Google Docs-style collaboration where changes from other users appear instantly and your actions feel immediate.

What Django developers get: Enterprise-grade real-time features without writing a single line of WebSocket code.

vue
<!-- Multiple users editing the same Django model -->
<template>
  <div v-for="task in tasks" :key="task.id" class="task-item">
    <input 
      v-model="task.title" 
      @input="task.save()"
      :class="{ 'being-edited': task.isBeingEditedByOthers }"
    />
    <button @click="task.completed = !task.completed; task.save()">
      {{ task.completed ? '✓' : '○' }}
    </button>
    <span v-if="task.lastEditedBy && task.lastEditedBy.id !== currentUser.id">
      Last edited by {{ task.lastEditedBy.username }}
    </span>
  </div>
</template>

<script setup>
import { useQueryset } from '@statezero/core/vue';
import { Task } from './models';

// This component automatically:
// - Shows changes from other users in real-time
// - Handles optimistic updates for snappy UX
// - Resolves conflicts when users edit simultaneously
// - Respects your Django permissions

const tasks = useQueryset(() => Task.objects.filter({ 
  project: currentProject.id 
}));
</script>

No WebSocket management. No conflict resolution code. No manual synchronization. Real-time collaboration just works.

Automatic Query Optimization

StateZero automatically optimizes your database queries behind the scenes. When you write simple JavaScript queries, StateZero intelligently applies select_related() and prefetch_related() to minimize database hits and maximize performance.

javascript
// You write this simple code
const orders = useQueryset(() => Order.objects
  .filter({ status: 'pending' }).fetch({fields: ['customer', 'customer__profile']})
);

// StateZero automatically optimizes it to:
// Order.objects.filter(status='pending')
//   .select_related('customer', 'customer__profile')
//   .prefetch_related('items')
//   .only('id', 'status', 'customer__name', 'customer__profile__email')
// Zero manual optimization needed!

Perfect for Modern Django + SPA Architecture

Building decoupled SPAs with AI tools? Bolt.dev, v0, and Cursor create beautiful Vue.js/React frontends, but connecting them to Django usually means weeks of API development.

StateZero eliminates all of that. Your AI-generated SPA components work immediately with your Django models.

Data Permissions That Scale

StateZero provides an expressive permission system that looks like DRF permissions but auto-applies to every query:

python
# Write permission classes like you know from DRF
class TaskPermission(AbstractPermission):
    def filter_queryset(self, request, queryset):
        # Users only see their own tasks
        return queryset.filter(created_by=request.user)
    
    def allowed_actions(self, request, model):
        # Control which operations users can perform
        return {ActionType.READ, ActionType.CREATE, ActionType.UPDATE}
    
    def visible_fields(self, request, model):
        # Control which fields users can see
        if request.user.is_staff:
            return "__all__"
        return {"id", "title", "completed", "created_by"}
    
    def editable_fields(self, request, model):
        # Control which fields users can modify
        return {"title", "completed"}
    
    def allowed_object_actions(self, request, obj, model):
        # Object-level permissions
        if obj.created_by == request.user:
            return {ActionType.READ, ActionType.UPDATE, ActionType.DELETE}
        return {ActionType.READ}

# Register with your model
registry.register(Task, ModelConfig(
    model=Task,
    permissions=[TaskPermission]
))
javascript
// Permissions automatically apply to all frontend queries
const tasks = useQueryset(() => Task.objects.all()); 
// ✅ Automatically filtered to user's tasks
// ✅ Only visible fields included
// ✅ Actions validated before execution

Custom Actions: Type-Safe RPC Between Frontend and Backend

Need custom backend logic in your SPA? StateZero's actions system lets you write Python functions and auto-generates type-safe JavaScript functions:

python
# Write backend functions in Python (in your Django app's actions.py)
from statezero.core.actions import action
from rest_framework import serializers

class SendNotificationSerializer(serializers.Serializer):
    user_id = serializers.IntegerField()
    message = serializers.CharField(max_length=500)
    
class NotificationResponseSerializer(serializers.Serializer):
    success = serializers.BooleanField()
    notification_id = serializers.CharField()

@action(
    serializer=SendNotificationSerializer,
    response_serializer=NotificationResponseSerializer,
    permissions=[IsAuthenticatedPermission]
)
def send_notification(user_id, message, request):
    # Your custom business logic here
    notification = Notification.objects.create(
        recipient_id=user_id,
        message=message,
        sender=request.user
    )
    
    # Send via email/SMS/push notification
    notification.send()
    
    return {
        'success': True,
        'notification_id': str(notification.id)
    }
javascript
// Auto-generated type-safe JavaScript function
import { sendNotification } from './actions/general/send-notification';

// Call your backend function directly from the SPA
const handleNotify = async () => {
  const result = await sendNotification({
    user_id: selectedUser.id,
    message: "Your order is ready!"
  });
  
  if (result.success) {
    console.log(`Notification sent: ${result.notification_id}`);
  }
};

// ✅ Full type safety with auto-generated TypeScript types
// ✅ Input validation with Zod schemas
// ✅ Permission checking before execution
// ✅ Error handling with StateZero exceptions
jsx
// AI tool generates this React SPA component
const ProjectDashboard = () => {
  const projects = useQueryset(() => Project.objects.filter({ 
    status: 'active',
    team_members: currentUser.id
  }));
  
  return (
    <div className="dashboard">
      {projects.map(project => (
        <ProjectCard key={project.id} project={project} />
      ))}
    </div>
  );
};

// Your decoupled SPA immediately works with Django:
// ✅ Your Django permissions automatically apply
// ✅ Real-time updates from other team members
// ✅ Optimistic updates for instant feedback
// ✅ No API endpoints needed
// ✅ Deploy SPA and Django backend independently

Modernize Django Apps with Decoupled SPAs

Got a Django app that's been running for years? StateZero gives you a safe path to modern decoupled SPAs:

  • Zero Django changes - Your models, views, admin, and business logic stay identical
  • Progressive enhancement - Add SPA pages alongside existing Django templates
  • Keep what works - Your existing Django admin, REST APIs, and workflows continue unchanged
  • True decoupling - Your SPA and Django backend deploy independently, scale separately

Framework Support for Django Developers

Build your decoupled SPA with Vue.js or vanilla JavaScript:

  • Vue.js - Native reactive integration with Django models ✅
  • Vanilla JavaScript - Works with any framework or no framework ✅
  • React - Hook-based integration (coming soon) 🚧
  • Svelte - Native store integration (coming soon) 🚧

Your Django Architecture Stays Clean

StateZero doesn't blur boundaries or create tight coupling. It creates a clean declarative data layer between your Django backend and decoupled SPA:

  • Django Backend: Models, business logic, validation, permissions (unchanged)
  • StateZero: Self-managing reactive state layer
  • JavaScript SPA: Pure presentation and user interaction

Deploy them independently. Scale them separately. Your Django architecture stays proper.

Django QuerySet Features You Know and Love

javascript
// Complete Django ORM API faithfully ported to JavaScript
const users = useQueryset(() => User.objects
  .filter({ is_active: true })         // snake_case field names
  .exclude({ role: 'guest' })
  .orderBy('-date_joined')             // camelCase method names
);

// All Django field lookups work
const recentOrders = useQueryset(() => Order.objects.filter({
  created_at__gte: lastWeek,           // Django-style field lookups
  total__gt: 100,
  customer__region: 'US'
}));

// Q objects for complex queries (just like Django!)
import { Q } from '@statezero/core';

const complexQuery = useQueryset(() => User.objects.filter({
  Q: [
    Q.AND([
      { is_active: true },
      Q.OR([
        { role: 'admin' },
        { role: 'staff' }
      ])
    ])
  ]
}));

// Aggregations, counts, exists(), first(), last()
const totalRevenue = useQueryset(() => Order.objects
  .filter({ status: 'completed' })
  .aggregate('total__sum')
);

// Get single instances with full error handling
const user = await User.objects.get({ username: 'john' });
// Throws DoesNotExist or MultipleObjectsReturned just like Django

// getOrCreate, updateOrCreate - the full Django ORM
const [order, created] = await Order.objects.getOrCreate(
  { customer: customerId, product: productId },
  { quantity: 1, status: 'pending' }
);

See It in Action

Try our live demo to experience:

  • Django models working in real-time
  • Optimistic updates that feel instant
  • Live collaborative editing
  • File uploads with Django models
  • All without a single line of API code

Get Started in 15 Minutes

  1. Add StateZero to your Django project (5 minutes)
  2. Generate JavaScript models and actions from your Django backend (1 command: npx statezero sync)
  3. Build your decoupled SPA using familiar Django syntax (5 minutes)
  4. Deploy independently (your Django backend and SPA are fully decoupled)

Ready to supercharge your Django app with modern SPAs?

→ Transform your first Django model in 15 minutes


Ready to Build Modern SPAs on Django?

Stop spending weeks building APIs and managing state. Start building the SPA features your users actually want.

Your Django backend is solid. Your models are battle-tested. Now make them work seamlessly in decoupled JavaScript SPAs.

StateZero: Your Django backend, supercharged for modern SPAs.