bpmn-engine

bpmn-moddle 9 vs 10

bpmn-engine declares bpmn-moddle as a peer dependency with the range >=9. You install it yourself and you are free to run the engine on either the 9.x or 10.x line:

npm install bpmn-engine bpmn-moddle smqp

The engine uses bpmn-moddle only to parse BPMN XML into a moddle context (new BpmnModdle().fromXML(source)). The moddle context is then handed to moddle-context-serializer to produce the persistable source context. Everything downstream of the parse — execution, getState(), recover(), resume() — is independent of the bpmn-moddle version.

What changed in 10

The output of fromXML() is unchanged between 9 and 10 — same { rootElement, elementsById, references, warnings } shape, same element ids and references. The breaking change is purely how the package is consumed:

  bpmn-moddle 9 bpmn-moddle 10
Module entry CommonJS ESM (type: module)
Parser export default export named export BpmnModdle
Import import BpmnModdle from 'bpmn-moddle' import { BpmnModdle } from 'bpmn-moddle'
require() require('bpmn-moddle') not available (ESM only)
// bpmn-moddle 9
import BpmnModdle from 'bpmn-moddle';

// bpmn-moddle 10
import { BpmnModdle } from 'bpmn-moddle';

bpmn-engine resolves whichever export shape the installed version provides, so the source option — where the engine parses the XML for you — works on both lines. No code changes are needed to move between 9 and 10.

One caveat for CommonJS consumers (require('bpmn-engine')): bpmn-moddle 10 is ESM-only, so the engine’s CJS bundle reaches it through Node’s require(esm) support — available since Node 20.19 / 22.12. On older Node, stay on bpmn-moddle 9 or migrate to import.

Backward compatibility of persisted state

Because the serialized source context and the runtime state are independent of the bpmn-moddle version, state saved by a deployment running bpmn-moddle 9 keeps resuming after an upgrade to bpmn-moddle 10 (and vice versa). recover() deserializes the embedded source context — or a source context you re-parse with the new version — without ever calling bpmn-moddle itself.

This is pinned down by the feature test test/feature/bpmn-moddle-backward-compatibility-feature.js, which:

  1. starts the mother-of-all process from a context parsed with bpmn-moddle 9, stops it at the first user task wait and saves the state;
  2. re-parses the same source with bpmn-moddle 10, recovers the v9 runtime state against the v10 source context, and resumes it to completion;
  3. asserts that the source context serialized via 9 and via 10 are byte-for-byte equal;
  4. runs the engine with the raw source option in a child process where bpmn-moddle resolves to 10, proving the engine’s own parse path handles the named export.