Workflows

The Axelor Open Platform provides a lightweight, declarative workflow engine. A workflow is bound to one model, starts from a single trigger, and walks a small graph of nodes — covering both automation ("when a record reaches state X, do Y") and human approval flows. You can write workflows as XML in a module or build them visually in the Studio designer; both are the same format.

Workflow designer

When to use a workflow

Use a workflow when the reaction to a record change is business logic that evolves: approval chains, notifications on state changes, follow-up record creation, timed escalations.

Alternative Difference

Actions

Actions run when the user interacts with a view. Workflows react to the record changing, whatever saved it — a form, a web service, an import.

Hibernate listeners

Listeners are code, compiled into a module, and run inside the saving transaction. Workflows are data — declarative, overridable, editable in Studio — and run after the transaction commits.

Job scheduling

Scheduled jobs run on a calendar. A workflow timer trigger runs per record, when that record’s own condition becomes true.

Concepts

Definition

The workflow itself — bound to one model, shipped as XML in a module or built in the Studio designer. See Definitions.

Trigger

The single <start> node says when the workflow fires: on create, on update (with watched fields and a condition), on a timer, on a message another workflow sends, or manually.

Nodes

From start, the engine walks script, agent, email, split, join, call, subflow, task, wait and send nodes until an end, with a boundary attached to any node it should be able to interrupt or catch. See Nodes; for how a split and a join make a choice, a fan-out or a race, see Branching and Joining.

Run

One execution of the graph. Failures are always recorded for auditing; set workflow.trace to runs or nodes to record every run (including successful and skipped ones). A run that reaches a task or wait node, or a call or subflow whose child parks — parks durably and resumes later: when a person decides, a timer elapses, a state condition becomes true, another workflow sends a message or broadcasts a signal it was waiting for, or the called workflow ends. See Execution.

A first workflow

A confirmation flow on sale orders: when an order becomes confirmed, large orders require a manager’s approval before the workflow records a confirmation note.

<?xml version="1.0" encoding="UTF-8"?>
<workflows xmlns="http://axelor.com/xml/ns/workflows">

  <workflow name="order-confirmation" model="com.axelor.sale.db.Order">

    <start id="start" on="update" watch="confirmed"
      when="self.confirmed == true" repeat="episode" next="check"/> (1)

    <split id="check" mode="one"> (2)
      <flow id="f1" when="self.totalAmount &gt; 10000" next="approve" title="Large order"/>
      <flow id="f2" default="true" next="notify"/>
    </split>

    <task id="approve" title="Approve large order"
      role="sales.manager" comment="reject" next="notify"/> (3)

    <boundary id="giveUp" host="approve" on="timer"
      delay="3" unit="day" next="notify"/>

    <script id="notify" next="done"><![CDATA[
      track(_t('Order confirmed'));
    ]]></script> (4)

    <end id="done"/>

  </workflow>

</workflows>
1 fires on updates of confirmed, only when it just became true, once per "episode" (it can fire again only after the condition turns false and true again)
2 routes on a JavaScript condition evaluated against the record
3 parks the run on a durable task for the sales.manager role; the <boundary> gives up after 3 days rather than waiting forever. See task and boundary
4 posts a confirmation note on the order’s message stream

To try it:

  1. Drop the file in src/main/resources/workflows/ of your module.

  2. Restart (or update the module). The workflow loads, validates and activates.

  3. Confirm an order and watch the run under Administration → Workflow Management → Workflow Runs.

Prefer building visually? The same graph takes a few minutes in the Studio workflow designer — no module or restart needed.

What you can rely on

  • Nothing runs inside your transaction. The save path only detects; the workflow dispatches after the transaction commits, in its own transaction. A workflow failure never rolls back the user’s save.

  • One expression language. All conditions and scripts are JavaScript. Trigger when conditions run in a restricted, sandboxed evaluator — in-memory field access only.

  • Near-zero save-path cost. Saving a record whose model has no active workflow costs a set lookup. State is persisted only where durability is unavoidable.