Python-native BPMN means you write a business process as plain Python code. No graphical editor, no hand-edited XML. The workflow lives in your codebase, next to the models it drives — versioned, reviewed, and tested like any other code.
Viewflow is an open-source BPMN workflow engine built
on this idea. You write a Flow class in Python; Viewflow runs it in
production and renders the BPMN diagram from the same source.
On this page
Traditional BPMN tools store the process as an XML file that a graphical designer generates. That XML is the source of truth, and everything else — your code, your tests, your review process — works around it. Python-native BPMN inverts that: the code is the process. Four things follow from that choice.
Because the workflow is code, every change to it is a normal commit. You see who
changed a gateway, when, and why — the same git blame and git log you
already use.
The bigger win is atomicity. A real change usually touches the model and the process together: you add a field, add the task that fills it, and add the migration in one commit. With XML-based tools, the model lives in code but the process lives in a separate designer. The two drift apart, and you re-sync them by hand. Code-first keeps them in lockstep.
from viewflow import this
from viewflow.workflow import flow
from . import models, views
class ApprovalFlow(flow.Flow):
process_class = models.ApprovalProcess
start = (
flow.Start(views.StartView.as_view())
.Next(this.approve)
)
approve = (
flow.View(views.ApproveView.as_view())
.Next(this.check)
)
check = (
flow.If(cond=lambda activation: activation.process.approved)
.Then(this.end)
.Else(this.start)
)
end = flow.End()
The diagram and the executable process come from this one class — no second file to keep in sync.
You test a Python workflow with the tools you already run in CI. Run a node in isolation, set the process state, and assert on which task comes next. No BPMN simulator, no clicking through a designer.
from django.test import TestCase
from viewflow.workflow import activation
class ApprovalFlowTests(TestCase):
def test_approved_moves_to_check(self):
process = ApprovalFlow.process_class.objects.create()
task = process.task_set.create(flow_task=ApprovalFlow.approve)
act = activation.Context(task)
act.prepare()
act.process.approved = True
act.done()
self.assertTrue(
process.task_set.filter(flow_task=ApprovalFlow.check).exists()
)
Because these are plain unittest (or pytest) tests, they run in
milliseconds and gate every pull request. Process logic stops being the
untested part of the system.
Large language models read and write Python well. They are far weaker at hand-writing valid BPMN 2.0 XML. When your process is a Python class, an AI assistant can propose a new gateway, refactor a branch, or explain what a flow does — working in the same language as the rest of your project.
This compounds with the points above. The model can read the git history to see how a process evolved, run the tests to check its own change, and submit the result as a reviewable diff. A workflow locked inside a proprietary designer offers the AI none of that context.
Code-first workflows are Python, so ordinary refactoring applies. Shared logic
goes in a function or a mixin. Common patterns become base Flow classes. You
reuse a view from one process in another. Copy-paste between XML diagrams gives
you none of this.
| Capability | Python-native BPMN (Viewflow) | XML / graphical BPMN |
|---|---|---|
| Source of truth | Python code | Generated XML file |
| Version control | Native git diffs and blame |
Opaque XML diffs |
| Code review | Standard pull requests | Separate tooling, if any |
| Testing | pytest / unittest |
Dedicated simulator |
| Model + process changes | One atomic commit | Two sources, synced by hand |
| AI support | First-class (plain Python) | Limited (BPMN XML) |
| Diagram | Rendered from the code | Drawn by hand |
Code-first is not a rejection of diagrams. Non-developers often need to read a process, and a rendered picture communicates better than a class. Viewflow keeps both: the code stays authoritative, and Viewflow renders the BPMN diagram from it. The picture never falls out of date with what runs. The PRO edition adds a visual frontend on top of the same code-defined flows.
Python-native BPMN is the practice of defining a business process in Python code — a class with tasks and gateways — instead of XML or a drag-and-drop designer. That code runs as the workflow and renders the diagram.
For engineering teams, yes on the axes that matter to them: version control, code review, automated testing, and atomic changes alongside the data model. Graphical designers remain useful for letting non-developers read a process, which is why Viewflow renders the diagram from the code rather than replacing it.
Yes. Viewflow is an open-source BPMN engine for Django. You define the process
as a Flow class and run it in production with support for parallel tasks,
persistence, and Celery. See the workflow documentation.
AI assistants generate and refactor Python well, but struggle with valid BPMN 2.0 XML. A process written as a Python class lets the assistant use the project’s real context — its git history, its tests, and its diffs — to make and verify changes.