Flowable JPA entities as process variables

Storing JPA entity references in Flowable process variables keeps business data in one source of truth, but it ties process state to your persistence model and transaction boundaries. This page explains how to decide, configure and verify that choice.

On this page

Flowable JPA entity variables: when a reference beats a copy

Teams that already keep customer, order or case records in JPA entities and want a Flowable process to act on them usually face one design choice: copy the values into process variables, store only the entity's ID, or store a reference to the entity itself. The Flowable JPA documentation describes the third option. It stores a reference to the JPA entity as a process variable and loads the entity when a delegate, expression or listener needs it. Queries on JPA process variables are also supported, so the process can be found by the entity it is working on. This matters most when the process must see the current state of a record at the moment it acts, not the state from when the process started.

A reference is the stronger choice when several steps read or change the same record, when the record can be edited outside the process, or when a stale copy would lead to a wrong decision, such as approving a loan against an old balance. A copy is simpler when the process needs a fixed snapshot for audit, because the history then shows exactly what the decision was based on. Storing only the ID sits between the two and works well when the entity is large or its loading rules are complex. Before choosing, confirm with your team which of these cases applies to each variable, since one process often needs all three.

Before you adopt references, check three things in your own environment. First, confirm how the entity is serialized into the variable store and that the entity class and its JPA mapping are stable across the release cycle, because in-flight instances must still load it after a deployment. Second, decide which Spring transaction owns the load and save, and test that a failed step rolls back both the process state and the entity change. Third, check the Flowable version you target against the Flowable JPA docs, since the example and the supported integration details are documented there and should be verified before you build on them.

Reference, copied value or plain variable: which option fits

This table compares storing a JPA entity reference, copying the fields the process needs into plain variables, and storing only the entity ID for a delegate to load. Read each row as a question you must answer for your process, then use the column that matches your answers. The main takeaway is that references give the freshest data at the cost of persistence coupling and a larger audit footprint, while copied values and IDs keep the process state stable and easier to review.

FactorEntity referenceCopied plain valuesEntity ID, loaded in a delegate
Data freshnessLoads current state from the database when read, so changes made after start are visibleFrozen at the moment of copy until the process updates the variableLoaded fresh at the point the delegate runs, so visible to later steps
Coupling to persistence modelHigh: the stored value depends on the entity class and its JPA mappingLow: only the copied fields and their types matterMedium: the ID type and the loader code depend on the entity model
Query supportSupports queries on JPA process variables, subject to the Flowable JPA docsStandard variable queries on the copied valuesQueries work on the ID only, so entity fields need a separate lookup
History size and auditStores a reference, but history shows what was read, so reviewers must confirm what the entity held at that timeLargest history if many fields are copied, but the snapshot is explicit and easy to readSmall history entries; the audit trail does not show the entity state unless you record it
Behavior when the entity changes or is deletedLoad may fail or return changed data, so the process needs a defined pathProcess keeps the old values and may act on stale dataDelegate must handle a missing record and decide whether to fail or continue
Best fitShort-lived processes where current data matters and the team controls the entity modelLong-running or audited processes where the decision must reflect the data at startProcesses that need current data at a few known steps and a simple, stable state

Setting up JPA entity variables in a Spring-based Flowable application

This sequence takes a Spring team from a bare Flowable starter to a verified setup where process variables hold entity references that load and query correctly, and roll back with the surrounding transaction.

  1. Add the Flowable Spring Boot starter

    The developer adds the Flowable Spring Boot starter for the process engine to the build, and adds the REST or CMMN and DMN starters only if the application needs them. Confirm the starter versions match the Spring Boot generation in use, since Flowable 8.0.0 requires Spring Boot 4 and does not support Spring Boot 3. Check the Spring Boot docs for the starter names and the actuator endpoint at /actuator/flowable. The step is done when the application starts, the engine creates its tables against the chosen database, and the actuator endpoint responds.

  2. Apply the JPA docs configuration

    The developer applies the configuration that the Flowable JPA docs require for storing entity references in process variables, including the JPA entity and variable settings described there. Confirm the supported database type and any MySQL precision requirement from the configuration docs before choosing the schema. The check is a deployed test process that writes one JPA variable and reads it back by its entity identifier without errors in the logs.

  3. Align the Flowable data source and transaction manager

    The platform team points Flowable and the application's JPA layer at the same data source and transaction manager, or confirms that both are deliberately separate and documented. Shared transactions are what let an entity save and a process step commit or roll back together. Ask the team to confirm this with the Spring configuration, not from memory. The check is a logged transaction boundary: a service method that saves an entity and then signals a process should show one transaction covering both writes.

  4. Define the entity and the variable access pattern

    The developer defines the JPA entity, its identifier type, and a single access pattern in a Spring bean that reads the entity by ID when a delegate or expression needs it. Keep the process variable to the identifier and avoid copying entity fields into variables, so the database stays the source of truth. Decide which variables stay plain values, such as a status string or a decision outcome. The check is a code review against this rule, plus a delegate that loads the entity inside the same transaction.

  5. Verify entity loading in an integration test

    The team writes an integration test that starts the Spring context, creates a process instance with the entity reference, and confirms that a delegate loads the current entity state. Include a case where the entity changed after the variable was set, to confirm the process reads the latest row. The check is a passing test that asserts the loaded field values, not the stored copy, and a test log that shows the expected query.

  6. Verify querying processes by entity

    The developer queries running process instances by the JPA variable, following the query pattern in the JPA docs, and tests both a match and a non-match. Confirm the query returns the expected instance count and that the query uses the identifier the team stored. The check is a test asserting the returned instance list and an indexed query plan reviewed on the target database, since the docs do not specify performance for large volumes.

  7. Verify rollback behavior

    The team forces a failure after the entity save and after the process signal in separate tests, then confirms that the entity change and the process state roll back together under the shared transaction manager. Also confirm that a failure in the delegate leaves the process at the previous wait state. The check is a test that asserts both the database row and the active activity are unchanged after the forced error, and a documented decision for any case where the transactions are separate.

How Spring transactions change what a process sees

When a service task runs inside the same Spring-managed transaction as the process step that started it, the entity the task loads is normally the same persistence context instance the surrounding code already holds. Changes the task makes to that entity are visible to later steps in that transaction and are written together with the engine's own state when the transaction commits. This keeps the process and the business data consistent, but it also means the task's behavior depends on how the Spring transaction is configured, not only on the BPMN model.

  • Shared persistence context: Confirm that the engine's transaction manager and your JPA transaction manager are the same bean, so both commit in one unit of work.
  • Flush timing: JPA may defer SQL until flush or commit, so a query issued mid-step may not reflect in-memory changes unless a flush happens first.
  • Lazy loading: An entity loaded in the task may need an open session to read associations, so decide whether the task fetches what it needs up front.
  • Delegate bean scope: Delegates that hold entity fields across calls can leak state between executions, so keep entities as local values.
  • Nested calls: A called sub-process or call activity that starts a new transaction changes the boundary, so confirm which steps share it.

Before relying on this behavior, test a task that updates an entity and then reads it back in a later step, and confirm the result with your Spring and Flowable versions.

Security and data exposure risks of entity variables

Storing entity references in process variables moves data access decisions out of the database and into the workflow engine. The cards below cover where that shift creates exposure, and each one names what the application must design because the engine will not do it for you.

Over-exposed entity fields

A process variable holding a JPA entity is readable by anyone who can query variables or view history, and the entity may carry fields that no task form should show, such as salary, national ID or internal risk scores. Because the engine resolves the whole entity, the fields visible to a process reader are whatever the entity exposes. Check which entity fields are reachable through variable APIs, REST responses and history queries, and restrict the entity or its serialization to what each consumer needs.

Stale or deleted records on resume

The engine stores only a reference, so when a waiting process resumes days later, the row it points to may have changed, been archived or been deleted. The process then acts on current data it did not see when it started. Decide whether each step must re-read and re-validate the entity, what happens when the record is missing, and whether the approval decision should capture the values the approver actually saw.

Access checks the engine does not perform

Flowable does not check whether the user completing a task is allowed to read or change the entity behind it. Anyone able to call the task API with a valid reference can act on that record unless your application checks ownership, tenant and role on every delegate, listener and service call. Confirm where those checks run, and test them with users who should be refused, not only users who should succeed.

PII retained in history tables

Variables that hold entity references are copied into runtime and history data when a process is recorded, so personal data can persist in history tables after the source record is purged or anonymized. Retention then depends on the history level you choose and on the cleanup schedule. Agree a retention period with your data protection owner, confirm which history tables store variable values, and define how erasure requests reach them.

Transaction and deletion gaps

Entity changes made in one transaction and process state saved in another can disagree after a failure, leaving a record updated while the process shows it was not, or the reverse. Deletion has the same problem when a process still references a row. Confirm that Spring transaction boundaries cover both the entity write and the engine call, and that your deletion path checks for active instances before removing data.

Limits to confirm before relying on entity variables

Storing JPA entity references in process variables couples process state to your persistence layer, Spring wiring and class definitions. The cards below cover the limits that vary by Flowable version, JPA provider and deployment, so each should be checked against the Flowable docs and your own tests before the pattern goes into production.

Flowable version and Spring Boot baseline

Entity variable behavior depends on the Flowable release and the Spring stack it runs on. Flowable 8.0.0 moved to Spring Framework 7 and Spring Boot 4 and dropped Spring Boot 3 compatibility, while Flowable 7 targeted Spring Boot 3 and Jakarta EE. Confirm which Spring Boot line your application uses and whether the JPA integration documented for that Flowable version matches your setup. Test the exact versions you plan to run.

Entity references across upgrades

A stored reference points to a table row and an entity class. When you upgrade Flowable, Spring or your persistence library, confirm that existing instances still resolve their references and that loading behaves the same. Add an upgrade test that resumes instances created on the previous version, because in-flight processes are the ones most likely to break.

Query support for your JPA provider

Querying processes by a JPA entity value depends on how the engine maps those variables to the database and on what your JPA provider and database support. Confirm the query syntax against the docs for your provider, and run each query you need against a realistic data volume. Do not assume that a query working in H2 in a unit test will behave the same way on your production database.

Serialization and class change risk

Entity classes evolve. Renaming a field, changing a relationship, moving a class to another package or changing its identifier type can leave stored references unreadable or pointing at the wrong data. Decide which entity changes are allowed while instances are running, document the rule for developers, and test resume paths after each entity change. Plain variables with explicit keys avoid much of this exposure.

Load cost on every resume

Each time a waiting process resumes, the engine can load the referenced entities to continue. Long-running processes that pass through many tasks, or that hold large object graphs, add database reads at every step. Measure the number of loads per instance, check whether lazy relationships are triggered, and confirm the behavior under the concurrency your async executor and job processing will produce.

Transaction and data freshness

A reference loads the current row, not the value that existed when the process reached the task. Confirm how Spring transaction boundaries wrap engine commands and entity loads in your design, and decide whether a process should see changes made by other users after it started. Write tests that change the entity between task steps and check the outcome your business rules require.

Questions teams ask before storing JPA entities in Flowable

What does this work cost, and what drives the effort up?

Cost follows the written scope, and DeployOpen does not publish a price list, so the quote is the figure to compare. The main drivers are how many process and case models carry entity references, how many JPA entities each model touches, how complex the transaction boundaries are, and how much of the existing Spring Data and JPA layer must change. Ask the quote to separate the one-time design and build work from any recurring support or retainer, and to list which test environments and data sets are included. Expect the effort to rise when entities are shared across services or when lazy-loaded relationships must be read inside a process step.

How long does a proof of concept take with a team that already knows Spring and JPA?

Duration depends mostly on how far the team already is with Spring transactions, JPA mappings and Flowable's Spring integration, so no fixed timeline applies. A team that already runs Spring Boot services with a working persistence layer can usually limit the proof of concept to one representative process that loads one entity, changes it and queries instances by that entity. A team new to either technology should add time for learning the transaction model and for agreeing the data model. Ask for the proof of concept scope in writing, including which entity, which process and which failure cases it will exercise.

What must our team provide before the work starts?

Three inputs decide whether the design holds up: a data model, a transaction design and representative test data. The data model should identify which JPA entities processes will reference, their identifiers and which fields must be current when a step runs. The transaction design should state where Spring transactions start and end relative to Flowable commands, and how a rolled-back step is handled. Test data should include entities in the states the process will meet, such as deleted or changed mid-process records. Confirm with your own architects who owns each entity and who can approve schema changes.

Can an internal team build this without an outside partner?

Yes, if the team has engineers who can work across Spring, JPA and the Flowable Java API and who can test process behavior. The engine is open source under Apache 2.0, and the Flowable JPA docs describe the reference pattern, so the knowledge is available to any team. The risks are less about the first build and more about keeping the pattern consistent as models change and as entities evolve. Decide who will own the reference pattern, the test suite and the upgrade path before deciding between an internal build and a partner-led one, and check that the in-house team has time for review.

What breaks when a referenced entity is deleted or changed while a process is running?

A stored reference only points to a row, so a deleted or changed entity surfaces later, when a step loads it. Engineers should design explicit handling for a missing entity, such as a failed job, a retry or a human task, and should decide whether the process reads the latest state or a snapshot. Test these cases before go-live, because the failure often appears hours or days after the change. Check the async executor behavior in the Flowable advanced docs for retries and failed jobs, and confirm how your team will monitor them.

Does storing entity references create a security or data protection concern?

It can, because a process variable that holds a reference may expose data to anyone who can read process instances, history or queries. Storing only an identifier limits what sits in the process tables, but the loaded entity still carries whatever the application authorizes at load time. The engine does not decide who may see an entity, so your application must add those checks. Confirm with your security and privacy teams which entities are personal data, how long history retains references, and where audit events are kept.

When are plain variables the safer choice?

Plain variables are safer when the value is small, stable and needed by the process as a record of what was decided, such as an amount, a status or a decision outcome. They are also safer when the process must show the exact data it used at the time, because a reference reloads current state and may differ from what was shown to an approver. Use entity references when the process needs live data, when many steps read the same record, or when queries must filter instances by entity. Document the rule in your design so that teams add new variables consistently.

Will this approach complicate a later upgrade or migration?

It can, because entity references tie process data to your application schema and to the Spring and JPA versions in use. Flowable's major releases change the platform baseline, so a team that upgrades Spring or Flowable should test that stored references still load and that JPA queries still return the expected instances. Plan the upgrade test set before the upgrade, and keep the entity mapping under version control. Confirm the baseline requirements for your target release in the Flowable 8.0.0 release notes before planning the work.

Where to read the Flowable JPA and Spring Boot documentation

Start with the Flowable JPA chapter before you write any entity-backed variable, because it defines the storage model you are committing to: the engine stores a reference to the entity and loads it when a task or expression needs it, rather than serializing a copy into the process variable table. The chapter also covers querying process instances by JPA variable values, and includes an example that combines Spring beans with JPA. Read it with your own domain model open, and confirm which entity types, identifier types and query patterns the documented example covers before you assume your design matches it. The chapter is the Flowable JPA documentation, and it is short enough to read in one sitting.

The Spring Boot chapter answers the questions the JPA chapter leaves open: how the Flowable starters wire the engine to your Spring data source, transaction manager and entity manager. Check that the engine and your application share one transaction boundary and one persistence context in your version, and confirm the starter version against the Spring Boot baseline your team already runs. Confirm the exact starter coordinates and supported Spring Boot line in the chapter for the Flowable release you plan to deploy, since the supported Spring Boot versions differ between Flowable major releases. The actuator endpoint described there is useful later for checking that entity-backed instances are running as expected.

The Advanced chapter explains the async executor, which matters here because a job that loads an entity from a variable runs on a worker thread, outside the request that started the process. Read how the executor picks up jobs and recovers expired locks, then test a job that loads an entity after the original transaction has committed and the entity has changed or been deleted. Plan for that failure case in your delegates before go-live, and confirm the executor settings for your cluster in that chapter.

How DeployOpen scopes and delivers Flowable entity variable designs

DeployOpen plans, builds, documents and supports Flowable engines inside your own infrastructure, including the decision on which JPA entities become process variables and which data stays as plain values. Engagements are fixed-scope, so the entity mapping, query rules and transaction design are agreed in writing before any build work starts.

How we scope

  • Inventory every JPA entity your processes would reference and the business reason each one must be carried as a variable.
  • Record which entity fields the process reads, which it writes, and which must never be held in process state.
  • Agree in writing how entity references are loaded, queried and refreshed, and where plain variables will be used instead.
  • Confirm your database, Spring version and Flowable version, since the scope depends on the versions your environment runs.

How we build

  • Implement entity references in delegates and Spring services so each task loads current data from the owning transaction.
  • Build the process queries your operations teams need against JPA process variables, with tests for each query path.
  • Align Flowable transactions with Spring transaction boundaries so a rollback never leaves a half-updated entity or stale reference.
  • Keep plain variable fallbacks for values that must be frozen at a point in time, such as an approved amount or a decision input.

How we hand over

  • Deliver the entity variable design document, listing each variable, its entity type, its owner and its lifecycle.
  • Provide automated tests covering entity loading, missing or deleted entities, and transaction rollback scenarios.
  • Document the query patterns, indexing expectations and history implications so your team can extend the design safely.
  • Run a handover session with your developers and operators, and record open decisions for your own team to own.

How we support

  • Review entity variable changes whenever your data model or Flowable version changes, before those changes reach production.
  • Offer ongoing support, upgrades and continuous testing as a retainer, scoped in writing to your environment.
  • Confirm with your team how entity schema changes will be coordinated with running process instances during each release.
  • Ask DeployOpen to quote retainer coverage separately from the initial fixed-scope design work.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.