Viewflow: a Django workflow library that keeps your process state in your own database
Reusable workflow library for Django
At a glance
- What is it?
- Viewflow is an AGPL-licensed Django package for building BPMN-style business workflows with ready-made views, a JSON store for process data, and timer and boundary-event nodes. It suits Django teams whose process logic has outgrown a status column but who do not want a separate BPM engine.
- Who is it for?
- Adopt Viewflow if your process logic lives in Django models and you want tasks, timers and boundary events in the same database as the rest of your data. Do not adopt it if you need a visual process designer, or if AGPL-3.0 with the additional permissions in LICENSE_EXCEPTION does not fit your distribution model and the commercial Viewflow PRO licence is not an option.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 13 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Viewflow solves, and who it is for
Django gives you models, forms and an admin. It does not give you a process. The moment an order has to move through bake, deliver and confirm, teams reach for a status column, then a status column plus a history table, then a hand-rolled state machine with permission checks scattered across views. Viewflow is aimed at that point. It is a reusable workflow library for Django that supplies the process model, the task rows, the views that drive transitions, and the frontend that lists what is waiting on whom.
The README describes it as low-code for developers with yesterday's deadline, and the quick start backs that up: a working pizza ordering flow is a Process subclass, a Flow class with four nodes, and two URL patterns. The audience is Django developers building internal business applications (order handling, approvals, onboarding) who want BPMN concepts without standing up a separate process engine and syncing state across a network boundary.
It is not a BPM suite for business analysts. There is no drag-and-drop modeler in the open-source package. Flows are Python classes, which means the people who change a process are the people who can read the codebase.
How a Viewflow flow actually runs
The mechanism is a Flow class whose attributes are nodes, chained with .Next(). Each node is a class from viewflow.workflow.flow: Start, View, End, and in 2.4.0 a longer list including Timer, StartTimer, ManualTask, BusinessRule, SendHandle, TerminateEnd, ErrorEnd, and the message, signal, escalation and conditional catch/throw events.
The process instance is a Django model. Your process_class subclasses viewflow.workflow.models.Process, and process data is stored through jsonstore fields rather than extra columns and joins. The README's PizzaOrder declares customer_name, address, toppings, tips_received and baking_time as jsonstore fields on a proxy model. A task row carries the state of one step, and the 2.4.0 release notes add a Task.scheduled field for timer due moments.
That last detail matters more than it looks. The release notes state that because the due moment is stored on the task row, a timer survives a broker restart, unlike celery.Timer. Due timers fire from the workflow_timers management command or the workflow_fire_timers celery beat task, so the scheduling source is explicit and you can run it without a broker at all.
Boundary events are declared on the host task before .Next(): .OnTimeout(delay, then) for deadlines and escalation, .OnError(then, code=...) to catch a background task failure. They interrupt by default; interrupting=False starts a parallel path. Compensation is the other half of that story: .CompensateWith(this.handler) registers an undo handler, and flow.CompensateThrow() runs handlers of completed tasks in reverse completion order, each at most once. This is the part of BPMN that hand-rolled state machines almost never get right, and it is where Viewflow earns its place.
Installing django-viewflow and running the pizza flow
Viewflow requires Python 3.10+ and Django 4.2+. The README gives the package name as django-viewflow, even though the project is called Viewflow. Install it with pip:
pip install django-viewflowThen add the apps to settings.py. viewflow.workflow is only needed if you use workflows, so a project that only wants the other components can leave it out.
INSTALLED_APPS = [
...,
'viewflow',
'viewflow.workflow', # if you need workflows
]The first real use is a process model. Subclass Process and declare the data as jsonstore fields. The README uses a proxy model so the fields land in the JSON store rather than as columns:
from viewflow import jsonstore
from viewflow.workflow.models import Process
class PizzaOrder(Process):
customer_name = jsonstore.CharField(max_length=250)
address = jsonstore.TextField()
toppings = jsonstore.TextField()
baking_time = jsonstore.IntegerField(default=10)
class Meta:
proxy = TrueThe flow itself is a class with a process_class and a chain of nodes. CreateProcessView and UpdateProcessView come from viewflow.workflow.flow.views and take a fields list; this is what renders the form at each step:
from viewflow import this
from viewflow.workflow import flow
from viewflow.workflow.flow.views import CreateProcessView, UpdateProcessView
from .models import PizzaOrder
class PizzaFlow(flow.Flow):
process_class = PizzaOrder
start = flow.Start(
CreateProcessView.as_view(fields=["customer_name", "address", "toppings"])
).Next(this.bake)
bake = flow.View(
UpdateProcessView.as_view(fields=["baking_time"])
).Next(this.deliver)
deliver = flow.View(
UpdateProcessView.as_view(fields=["tips_received"])
).Next(this.end)
end = flow.End()Finally, register the flow with the site and wire the URLs. AuthViewset supplies the account routes the frontend expects, and FlowAppViewset takes the flow class plus an icon name:
from django.urls import path
from viewflow.contrib.auth import AuthViewset
from viewflow.urls import Application, Site
from viewflow.workflow.flow import FlowAppViewset
from my_pizza.flows import PizzaFlow
site = Site(
title="Pizza Flow Demo",
viewsets=[FlowAppViewset(PizzaFlow, icon="local_pizza")],
)
urlpatterns = [
path("accounts/", AuthViewset().urls),
path("", site.urls),
]Run migrations and start the server, then open the browser. The README states you can create and track pizza orders through the workflow at that point. A runnable version of exactly this example lives in demo/helloworld in the repository, which is the fastest way to see the expected screens before adapting it.
Where Viewflow gets in the way
The licence is the first constraint. Viewflow Core is AGPL-3.0 with additional permissions described in LICENSE_EXCEPTION. The README compares those permissions to the GNU GCC Runtime Library licence and says the package is friendly for commercial development, and it notes that if you already use Linux the licence likely brings nothing new to your stack. That is the project's own framing, not a legal opinion, and the boundary between the open-source core and Viewflow PRO matters: PRO is a separate commercial package installed from a private index with a licence id, and its commercial licence is what allows private forks and modifications. If your deployment model depends on modifying and redistributing the workflow engine without publishing changes, read LICENSE_EXCEPTION and COMM-LICENSE before writing flow code, not after.
The second constraint is the shape of the API. Flows are Python classes, so a process change is a code change and a deploy. There is no modeler in the open-source package, and the README does not document a way to edit a running definition from the UI. Teams that expect business users to redraw a process will find Viewflow the wrong tool.
The third is operational. Timers need something to fire them: the workflow_timers management command or the workflow_fire_timers celery beat task. The README does not document rollback of a deployed flow definition, and it does not describe what happens to in-flight process instances when the Flow class changes. Treat flow definitions as schema and plan migrations accordingly. The README also does not document a versioning or migration story for jsonstore field changes on existing process rows.
Viewflow compared with django-fsm and django-river
django-fsm is the obvious alternative for a single model with states and transitions. It is a decorator-based state machine: you mark transitions, guard them with permissions, and call them from views. It has no process model, no task rows, no per-step forms, and no frontend. The 2.4.0 release notes describe Viewflow as offering a drop-in replacement for django-fsm, which is the honest way to read the relationship: Viewflow is what you move to when the state machine needs to be a process with a queue of work, and it tries not to make that move painful for code already written against django-fsm.
django-river is the closer comparison in intent. It stores transitions as database rows and lets you define them at runtime, which is the opposite trade-off from Viewflow's Python classes. If the requirement is that an administrator changes the approval chain without a deploy, django-river's data-driven model is the better fit. If the requirement is that the process is reviewed, tested and versioned like the rest of the codebase, Viewflow's class-based definitions are.
The other alternative is not a library at all: a separate BPMN engine with Django as a client. That buys a visual modeler and a language-agnostic process definition, and it costs a second state store, a sync layer, and a distributed transaction problem every time a task completes. Viewflow's bet is that keeping process state in the same database as the business data removes more work than it adds.
Maintenance, releases and upgrade cost
The repository is not archived and the last push was on 2026-09-18, so the project is being worked on. Releases in the 2.x line are frequent: 2.3.1 on 2026-06-30, 2.3.2 on 2026-07-06, and 2.4.0 on 2026-07-30. The 2.4.0 notes call it the largest feature release of the 2.x line, adding complete BPMN 2.0 node coverage, JSON Store documents, and the django-fsm drop-in.
That pace has a cost. 2.4.0 adds a Task.scheduled field with a migration included, which means upgrading is not a pip install alone. The package requires Django>=4.2 and django-jsonstore>=26.7.0, and setup.py pins above 0.5.1 of django-jsonstore because that was the deprecated merged-into-viewflow release. Classifiers list Django 4.2 through 6.0 and Python 3.10 through 3.13, so the supported surface is wide, but a project on an older Django will need to move before it can move Viewflow.
The frontend is not a static asset you ignore. package.json defines the build scripts, with vite build behind the vite script and a python-integration-tests script that expects PostgreSQL at postgres://viewflow:viewflow@localhost/viewflow and Redis at redis://127.0.0.1:6379/1. If you fork the UI, you are maintaining a TypeScript and Solid build alongside your Python code.
Editorial conclusion
Adopt Viewflow if your process logic lives in Django models and you want tasks, timers and boundary events in the same database as the rest of your data. Do not adopt it if you need a visual process designer, or if AGPL-3.0 with the additional permissions in LICENSE_EXCEPTION does not fit your distribution model and the commercial Viewflow PRO licence is not an option. Before committing, run the pizza example from the README on your Django version, confirm the workflow_timers command or workflow_fire_timers celery beat task is scheduled if you use flow.Timer, and read LICENSE_EXCEPTION against how you ship the software.
Frequently asked questions
What is Viewflow in Django?
Viewflow is a reusable workflow library for building business applications with Django. It provides a Process base model, flow classes made of nodes such as Start, View and End, ready-made create and update views, and a frontend for listing and tracking tasks.
How do I install Viewflow?
Install the package with pip install django-viewflow, then add 'viewflow' and, if you need workflows, 'viewflow.workflow' to INSTALLED_APPS. Viewflow requires Python 3.10+ and Django 4.2+.
Does Viewflow need Celery to run timers?
No. The 2.4.0 release notes state that the due moment of a flow.Timer is stored on the task row, so due timers can fire from the workflow_timers management command or from the workflow_fire_timers celery beat task. The management command path does not require a broker.
What is the difference between Viewflow Core and Viewflow PRO?
Viewflow Core is the open-source AGPL-3.0 library with base classes you build on. Viewflow PRO is a separate package installed from a private index that adds ready-to-use features and third-party integrations, and its commercial licence allows private forks and modifications.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/viewflow-viewflow)