BPMN diagrams
from code,
not clicks.
A fluent TypeScript API that generates deployable BPMN 2.0 diagrams with auto-layout — for developers, automation platforms, and AI agents.
Analysts still review and edit everything visually. It replaces the copy-paste-redeploy gap between the diagram and production, not the diagram.
The panel beside this text cycles through five example scripts, typing out a BPMN Kit builder call and rendering the resulting diagram live. The same builder API is available as static, editable code in the playground below.
The same process, two ways.
<bpmn:definitions
xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:zeebe="http://camunda.org/schema/zeebe/1.0">
<bpmn:process id="p" isExecutable="true">
<bpmn:startEvent id="s">
<bpmn:outgoing>Flow_1</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:serviceTask id="t">
<bpmn:extensionElements>
<zeebe:taskDefinition type="worker"/>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1</bpmn:incoming>
<bpmn:outgoing>Flow_2</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:endEvent id="e">
<bpmn:incoming>Flow_2</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1" sourceRef="s" targetRef="t"/>
<bpmn:sequenceFlow id="Flow_2" sourceRef="t" targetRef="e"/>
</bpmn:process>
<bpmndi:BPMNDiagram>
<bpmndi:BPMNPlane>
<bpmndi:BPMNShape bpmnElement="s">
<dc:Bounds x="152" y="82" width="36" height="36"/> import { Bpmn } from "@bpmnkit/core";
const xml = Bpmn.export(
Bpmn.createProcess("my-flow") // fluent API
.startEvent("start") // trigger
.serviceTask("task", {
name: "Do Something",
taskType: "my-worker", // Zeebe type
})
.endEvent("end")
.withAutoLayout() // Sugiyama
.build()
);
// ✓ Valid BPMN 2.0 XML
// ✓ Auto-layout applied
// ✓ Zeebe extensions set What you get
Auto-layout
Sugiyama engine with orthogonal edge routing. No coordinate math, ever.
Type-safe
29 guards narrow the BpmnFlowElement union. Errors are instanceof-catchable with machine-readable codes.
Roundtrip fidelity
Parse → modify → export with no data loss. Zeebe extensions, custom namespaces and DI preserved.
Zero dependencies
Pure ESM, tree-shakeable. Browsers, Node, Deno, Bun and edge runtimes.
DMN & Forms
The same builder pattern for DMN 1.3 decision tables and Camunda form JSON, referenced from the process.
LLM-friendly format
A compact intermediate form fits a whole diagram in one prompt. The SDK validates and renders what the model returns.
Six packages, pick what you need
Independently versioned and pre-1.0, developed in the open under MIT. Everything below is installable today.
Camunda 8, end to end
A fully typed REST client — 180 methods across 30+ resource classes, three auth
modes, retry with backoff — plus casen, a terminal UI for the same API.
And 100 built-in OpenAPI specs covering
18,145 endpoints that generate typed
Zeebe connector templates. Browse the catalog →
import { CamundaClient } from "@bpmnkit/api";
const client = new CamundaClient({
baseUrl: "https://api.cloud.camunda.io",
auth: {
type: "oauth2",
clientId: process.env.CAMUNDA_CLIENT_ID!,
clientSecret: process.env.CAMUNDA_CLIENT_SECRET!,
tokenUrl: "https://login.cloud.camunda.io/oauth/token",
audience: process.env.CAMUNDA_AUDIENCE!,
},
});
// Start a new instance of an already-deployed process
const instance = await client.processInstance.createProcessInstance({
processDefinitionId: "my-flow",
variables: { orderId: "ord-123" },
});
// React to lifecycle events
client.on("request", (e) => console.log(e.method, e.url));
client.on("error", (e) => metrics.inc("api.error")); Interactive TUI over the same API: connection profiles for dev/staging/prod, processes, jobs, incidents, decisions and variables, with scrollable tabular output. Full command reference →
This terminal animates a demo session of casen, the BPMN Kit CLI: navigating the main menu, opening the process command group, listing process definitions and viewing a tabular result.
Three steps to a deployable diagram
Install
$ pnpm add @bpmnkit/core
# optional
$ pnpm add @bpmnkit/api
$ pnpm add -g casen $ bun add @bpmnkit/core
# optional
$ bun add @bpmnkit/api
$ bun add -g casen $ npm install @bpmnkit/core
# optional
$ npm install @bpmnkit/api
$ npm install -g casen $ yarn add @bpmnkit/core
# optional
$ yarn add @bpmnkit/api
$ yarn global add casen Build a process
import { Bpmn, exportSvg } from "@bpmnkit/core";
const defs = Bpmn.createProcess("hello")
.startEvent("start")
.serviceTask("task", {
name: "Hello World",
taskType: "greet",
})
.endEvent("end")
.withAutoLayout()
.build();
const xml = Bpmn.export(defs); // ✓ BPMN 2.0 XML
const svg = exportSvg(defs); // ✓ SVG image, zero deps Simulate, then deploy
import { Engine } from "@bpmnkit/engine";
// Simulate the process in-process — for tests and local development.
// Deploying to a real Camunda 8 cluster? See the API client below.
const engine = new Engine();
engine.deploy({ bpmn: defs });
engine.registerJobWorker(
"greet",
async (job) => {
console.log("Hello!");
job.complete();
}
);
engine.start("hello");
The engine is an in-process simulator for tests and demos. Production execution
runs on Camunda 8 / Zeebe via @bpmnkit/api.
Decisions and forms, same builder
DMN 1.3 decision tables and Camunda form JSON come out of the same fluent API, and a BPMN process can reference both.
import { Dmn } from "@bpmnkit/core";
// Build a DMN decision table
const dmnDefs = Dmn.createDecisionTable("Eligibility")
.name("Loan Eligibility")
.input({ label: "Credit Score", expression: "creditScore", typeRef: "integer" })
.input({ label: "Income", expression: "income", typeRef: "number" })
.output({ label: "Eligible", name: "eligible", typeRef: "boolean" })
.output({ label: "Max Amount", name: "maxAmount", typeRef: "number" })
.rule({ inputs: [">= 700", ">= 50000"], outputs: ["true", "500000"] })
.rule({ inputs: [">= 600", ">= 30000"], outputs: ["true", "200000"] })
.rule({ inputs: ["-", "-"], outputs: ["false", "0"] })
.build();
const xml = Dmn.export(dmnDefs); // ✓ valid DMN 1.3 XML DMN decision tables
Define inputs, outputs and rules; the SDK emits valid DMN 1.3 XML with
auto-computed DMNDI layout. Dmn.createDecisionTable(id) builds
it, Dmn.export(defs) serialises it, Dmn.layout(defs)
positions it.
import { Form } from "@bpmnkit/core";
// Build a Camunda form from code
const form = Form.makeEmpty("ApplicationForm");
// Forms are JSON-based; extend with fields:
// { type: "textfield", key: "applicantName", label: "Applicant Name" }
// { type: "number", key: "requestAmount", label: "Requested Amount" }
// { type: "select", key: "loanType", label: "Loan Type",
// values: [{ label: "Personal", value: "personal" },
// { label: "Business", value: "business" }] }
// { type: "submit", label: "Submit Application" }
const json = Form.export(form); // ✓ valid Camunda form JSON Camunda forms
Scaffold Camunda form JSON from code. Form.makeEmpty(id) gives a
baseline structure; extend it with typed fields for text inputs, numbers and
dropdowns.
import { Bpmn } from "@bpmnkit/core";
// BPMN process referencing a DMN decision and a Camunda Form
const defs = Bpmn.createProcess("loan-application")
.name("Loan Application")
.startEvent("start", { name: "Application Received" })
// User task linked to a Camunda Form by ID
.userTask("collect-data", {
name: "Collect Applicant Data",
formId: "ApplicationForm",
})
// Business rule task evaluated by a DMN table
.businessRuleTask("check-eligibility", {
name: "Check Eligibility",
decisionId: "Eligibility",
resultVariable: "eligibilityResult",
})
.exclusiveGateway("gw", { name: "Eligible?" })
.branch("approved", (b) =>
b.condition("= eligibilityResult.eligible")
.serviceTask("disburse", {
name: "Disburse Loan",
taskType: "disburse-loan",
})
.endEvent("end-ok", { name: "Loan Approved" }),
)
.branch("rejected", (b) =>
b.defaultFlow()
.serviceTask("notify", {
name: "Notify Applicant",
taskType: "send-rejection-email",
})
.endEvent("end-rejected", { name: "Rejected" }),
)
.withAutoLayout()
.build(); BPMN with DMN & form references
Link a process to a decision table via businessRuleTask and to a
form via userTask. Both use Zeebe extension attributes, so the
process is immediately deployable to Camunda 8.
Try the builder in the browser
Write Bpmn, Dmn and Form builder expressions.
Press Ctrl+Enter (or ⌘ Enter) to render. Nothing to install.
Analysts model it. Developers ship it.
Standard BPMN 2.0 files open in any tool, including Camunda Modeler. Nothing here is a lock-in format. Explore use cases →
Faster process changes
Updates ship through code review — versioned, tested, audit-traceable.
AI-drafted workflows
Describe a process in plain language; get a valid diagram analysts review visually.
No license fees
MIT, open source, standard files. Leave whenever you want.