Flowable transient variables

Transient variables let a Flowable process pass data between steps without writing it to the database. This page explains when they are lost, how to use them safely for large payloads and API responses, and what to confirm before you build.

On this page

When Flowable transient variables fit your process

Flowable transient variables let a process pass data between steps without writing that data to the database, so the value exists only while the engine is actively executing the process. Teams reach for them when a value is needed for a few steps but should not be persisted, such as a large payload received from a caller, an intermediate calculation, or a response body that the REST layer returns to the caller once the process reaches a wait state. Persisting such values can bloat the variable tables, widen the history record and place sensitive content in storage it does not need to occupy, so the decision is often as much about data retention as about performance.

This page covers how transient variables are set and read, which points in a process lose them, how they fit large payloads and API responses, and the mistakes teams make when they assume a transient value will survive a wait state. Use it as a design guide before you build, then confirm every behavior described here against the Flowable documentation for the version you run, since variable handling has changed between major releases. The Flowable advanced documentation and the Flowable configuration documentation are the first places to check, and a test in your own environment will confirm what your version actually does.

Transient variables compared with persisted variables

This table compares transient variables, persisted process variables and an external storage reference for large content across wait states, history, database writes and typical use. Read each row as a design question: what must survive a wait, what must be auditable, and what should stay out of the database. Confirm each behavior against the Flowable version and configuration you run, because details can differ between releases.

AspectTransient variablePersisted process variableExternal reference
Survives a wait stateNo, cleared once the current execution step endsYes, restored when the instance resumesYes, the reference is stored and the content stays outside the engine
Appears in historyNormally no, confirm with your history levelYes, subject to history configurationThe reference value may appear, not the content
Written to the databaseNoYes, as serialized variable dataOnly the reference string or identifier
Typical fitPassing data between adjacent steps in one transactionBusiness state needed for routing, audit or later stepsDocuments, large payloads or files shared with other systems
Size sensitivityLow impact on the databaseLarge values slow reads and writesContent size is handled by the storage system
Retrieval after resumeNot available, must be re-fetched or recomputedRead directly from the instanceFetch content by reference using a service task or API call
Access controlLimited to the code path that sets itGoverned by engine and application access checksGoverned by the storage system and its own permissions
Main riskExpecting the value after a wait or in a later API callStoring sensitive or oversized content in variablesOrphaned or unlinked content and stale references

Common mistakes that lose data or leak payloads

Most transient variable failures come from one misunderstanding: the engine does not keep these values across wait states, and nothing warns you when they are gone. The cards below cover the mistakes that cause lost data, bloated storage and exposed payloads, along with the test and logging habits that catch them before production.

Expecting a value after a user task

Teams set a transient variable before a user task, complete the task, and then find the value missing in the next activity. The engine discards transient variables when the execution reaches a wait state, so the value does not survive the task. Fix it by storing anything needed after the wait as a regular process variable, and check each wait state in the model for downstream reads.

Reading transient values in later service tasks

A service task placed after a timer, receive task or user task may read a transient variable that was set earlier in the same path and get null. The bug often appears only in production, where the wait is real, while tests run straight through. Fix it by tracing every read back to its write and confirming that no wait state sits between them.

Storing large binaries in persisted variables

Developers sometimes pass documents or images as variable values to keep them out of the database, then discover that any variable which is persisted is written to storage with the instance. Transient variables avoid that write, but large content still sits in memory for the whole execution path. Fix it by passing a reference such as an object storage key or document ID and fetching the content where it is needed.

Writing sensitive values to logs

Delegates and listeners often log the full variable map while debugging, which can copy personal data, tokens or account details into application logs and log shipping systems. Transient status does not protect a value once it is printed. Fix it by logging variable names or identifiers only, and reviewing delegate code and log levels in each environment.

Returning transient values as API responses without checks

Teams that build REST responses from variables may include a transient value that is only present on some paths, or expose internal fields that were never meant for clients. The response then varies by path and can leak data that the caller should not see. Fix it by defining the response contract explicitly and mapping only approved fields from the instance.

Testing only the path without a wait

Unit tests that run a process straight through without a wait state pass even when transient values disappear in production. The test confirms the logic but not the persistence boundary. Fix it by adding a test that stops at each user task, timer or receive task, then resumes and asserts that every needed value is still present.

Setting up transient variables in a process application

This sequence takes a team from confirming its Flowable version to proving, with a test and a logging review, which values survive a wait state and which are discarded. The result is a process where each variable's lifetime is a deliberate choice.

  1. Confirm the Flowable version and engine in use

    The engineering lead records the Flowable version, the engine modules on the classpath (BPMN, CMMN or DMN), and whether the application runs embedded through Spring Boot starters, a servlet container or the REST application. Behavior and API details can change between major releases, so this record anchors every later decision. Done means a short version note sits in the project README or architecture record and every developer on the team can point to it.

  2. Read the variable documentation for that version

    A developer reads the variable section of the Flowable documentation that matches the recorded version, paying attention to how transient variables are set, read and cleared, and what happens to them at wait states such as user tasks, timers and receive tasks. Upgrades may bring a new Spring or Java baseline, so the reader also checks the release notes for the same version line. Done means the team has written down the three or four behaviors it will rely on and where each one is documented.

  3. Classify each value as transient or persisted

    The process owner and developer walk through every value the process needs and label it as transient (needed only between two adjacent steps, such as a large payload or an API response body) or persisted (needed after a wait state, for routing, audit or a later task). They also flag values that must never be stored in the database for data protection reasons. Done means a table lists each variable name, its lifetime, its owner and the activity that reads it.

  4. Write the service task or expression that sets the value

    A developer implements the service task, delegate or expression that sets the transient variable using the engine's transient setter, keeping the write as close as possible to the activity that produces the data. Field-injected delegates should not hold request data in instance fields, because a shared delegate can leak values between executions. Done means the code compiles, the variable name matches the classification table, and a code review confirms no persisted variable is accidentally written as transient.

  5. Test that the value survives or disappears at a wait state

    The developer adds a JUnit test that starts the process, runs the transient-writing step, reaches a wait state, then reads the variable through the same process execution and asserts the documented behavior. The test should also assert that a persisted variable remains after the same wait. Done means both assertions pass in the continuous build and a failing change to the classification would break the test.

  6. Map the response from the same execution

    When the transient value feeds an API response, the developer maps it from the execution that produced it, before the process reaches the wait state, instead of reading it later from the database. The REST or service layer returns the mapped response, and the team checks that large payloads are not duplicated in process history. Done means an integration test shows the response body contains the expected data and the database holds no copy of the payload.

  7. Review logging and history for leaked values

    The operations or security reviewer checks application logs, the history tables and any audit events to confirm that transient values were not written there by a debug statement, a default history level or a listener. Because transient data is meant to stay in memory, any appearance in storage is a defect to fix before release. Done means a reviewer signs off on a sample run and the team records which history level is configured.

Choosing a pattern for large payloads and API responses

When an external system sends a large document, file or dataset, the process rarely needs the whole payload in its variables. The usual approach is to store the content in a system built for it, such as object storage or a document store, and pass only a reference, identifier or checksum into the process. The step that needs the content fetches it, so the wait states in between do not carry the bytes.

  • Store the content outside the engine: Keep the bytes in storage you control and pass the reference.
  • Persist only what the engine must hold: Keep values needed for routing, decisions or audit as persistent variables, and mark the rest transient.
  • Fetch content where it is used: Read the payload inside a delegate or worker so the value is not carried across waits.
  • Enforce access on the reference: A reference is a pointer, so the storage system must check authorization on every read.

Confirm in the Flowable docs how your version serializes variables and whether transient values survive the wait states your process uses, then test with a payload close to your largest expected size.

The trade-off is an extra system to operate, with its own retention rules, backups and failure modes during retrieval.

Security and operational risks of short-lived data

Transient variables keep data out of the database, which removes some risks and creates others. The cards below cover what stays in memory, what the REST API can expose, what auditors can and cannot reconstruct, and how failures show up when a request crosses nodes.

Sensitive values in memory and logs

A transient variable lives in the engine's memory for the duration of the work that needs it, so it never reaches the database tables that encryption and backup policies usually cover. The risk moves to logs, debug output and exception messages, where a payload or token can be printed while a delegate fails. Check your logging configuration for the engine and your delegates, and confirm that error handling does not echo variable values.

REST responses expose variables

When a task or process instance is returned through the REST API with variables included, transient values can appear in the response even though they were never persisted. Flowable does not decide which variables a caller may see. Your application must filter responses and check that the caller may read each task or instance before returning anything, and tests should cover that path.

Audit trail gaps for unpersisted data

History tables record variable changes only for values that are stored, so a transient value leaves no row to review after the process moves on. If an audit or incident review needs to show what a service call received, the record must come from your own application logs or events. Confirm with your compliance team which evidence they require before you rely on transient values for regulated steps.

Cluster routing and lost context

In a cluster, the request that starts a step and the node that continues the process may differ, and a transient value set on one node is not available on another. Async jobs and timers that run on another node will not see values set earlier in the same request. Review every place where a transient value is read after a wait state, and test the flow with more than one node running.

Failed and stalled executions

A failed job that depends on a transient value will not succeed on retry, because the value is gone. The async executor recovers jobs whose locks expire and passes them to other nodes, but it cannot restore data that was never stored. Monitor failed jobs and stalled instances, and record enough identifiers in your own logs to re-create the input.

Ownership of access checks

Flowable provides the engine and its APIs, but it leaves authorization decisions to the application that calls them. Each team that builds a task list, a status screen or an integration must decide who may see which variables, and whether that check runs in the service layer or at the API gateway. Document these owners before go-live so that transient values do not slip past a check that no one was assigned to write.

What buyers ask before adopting transient variables

Do transient variables survive a wait state in Flowable?

No, transient variables are held in memory for the current execution and are not written to the database. When the engine saves the process at a wait state such as a user task, a timer or an async job, the transient values are gone when the work resumes. Ordinary process variables are stored and remain available. Confirm this behavior for your engine version and each wait state you use in the Flowable docs, then cover it with a test that pauses the process, resumes it and reads the variable. A value set before a wait state and read after it is often missing, and a later gateway condition may fail quietly, so this test is the cheapest way to settle the question for your model.

What does adopting transient variables cost?

Most of the cost is engineering time spent finding where transient data is set and read, deciding what must persist, and testing each wait state. Design and test work is largely one-time, but it recurs whenever a model changes, a new wait state is added or the engine is upgraded. Cost rises with the number of process definitions, the number of wait states between where data is set and where it is read, and the number of API responses built from large payloads. Your team pays its own engineers, while a partner bills against a written scope. DeployOpen does not publish a price list. A quote follows a written scope that lists the processes, wait states, payload sources and test coverage, so ask for effort broken down by those items.

How long does adopting transient variables usually take?

Duration depends on how many process definitions use transient data, how many wait states sit between writing and reading that data, and how many integrations depend on the results. A small model with one or two processes is a different job from a set of processes that feed API responses across several services. DeployOpen does not publish a timeline, and duration is agreed in the written scope before work starts. Ask for a phased plan that separates the audit of current variable use, the design of what must persist, the changes to each process and the test runs in a non-production environment. Each phase should name the deliverable it produces.

What must our team provide before work starts on transient variables?

Your team needs to provide the material that shows how data moves through the process today. Prepare the following before the first working session:

Can our internal team adopt transient variables without a partner?

Yes, a team that knows Java, the Flowable APIs and JUnit can make this change, provided it has time to test each wait state and a non-production environment that matches production. The hardest part is rarely the code change itself. It is finding every place where data crosses a wait state, including timers and async jobs, which can run on other nodes and at a later time. Teams that handle this well usually assign one owner for the variable inventory and one for the tests. If your team lacks that time or has no one who has worked with the engine's job execution, a fixed-scope engagement can take on part of the work.

When should we bring in a partner for Flowable transient variables?

Bring in a partner when the change spans several process definitions, when the models run in production with live traffic, or when large payloads or API responses depend on data that must survive a wait state. A partner also helps when the same mistake would have to be fixed in many places at once. DeployOpen plans, implements, tests and documents self-hosted open-source platforms inside your own infrastructure, and most engagements are fixed-scope with deliverables and timelines agreed in writing before work starts. Ongoing support and continuous testing are available as retainers. For a hypothetical example, a team with three processes and a clear test suite may need only a short review, while a team with twenty processes and no tests may need a full engagement.

Can transient variables carry large payloads or API response data?

Transient variables can hold data for the current execution, but they should not be used to carry large payloads from one wait state to the next, because they are lost at the wait state and any data you need afterward must be stored elsewhere. A common pattern is to store only an identifier or reference in a persistent variable, then load the full payload from your own database or object storage when the API response is built. Check how your REST layer reads variables and confirm which values are available after the engine saves the process. Document the pattern in each process model so later changes do not reintroduce the problem.

What to confirm in your environment before you build

Transient variables behave differently across engine versions, models and deployment layers, so the details matter before any design is fixed. The cards below cover the checks that connect engine behavior, payload handling, persistence and the infrastructure in front of the engine.

Behavior in your exact Flowable version

Confirm how transient variables behave at wait states in the Flowable version you run, and test it on that version rather than relying on older examples. Flowable 8.0.0 moved to Spring Framework 7 and Spring Boot 4, so a version upgrade can change more than the engine API. Write a short test that pauses a process at a user task and checks which variables survive the wait.

Default JSON library after upgrade

If a transient payload is serialized to JSON for an API response or a message, confirm which JSON library your code path uses. The 8.0.0 release notes make Jackson 3 the default with a Jackson 2 compatibility layer. Serialization differences can change field names, date formats or null handling in responses your clients already depend on.

Variable types and expressions in models

List which variable types, Java objects and expression forms your BPMN, CMMN and DMN models read. A transient value used in an expression at a later step must still resolve after a wait state, and a missing value often fails silently in a gateway condition. Review each condition and listener that touches a transient variable before you assume it is available.

Database and history settings

Confirm the target database and its history configuration, since the engine supports several database types. Transient values are not written to the database, so check which values the history tables record and how long they stay. Verify timestamp precision on your database too, because older MySQL versions below 5.6.4 lack millisecond precision.

Timers and async jobs with transient data

Timers and asynchronous jobs run later, often on another node, so any transient value they need will not be there. Decide which data must be persisted before a timer or async boundary and which can be rebuilt from a database lookup. Test a timer firing after a restart and a job picked up by a different node.

Gateway and REST size and timeout limits

Confirm the request body size, response size and timeout limits set by your API gateway, load balancer and the Flowable REST deployment. Large payloads that pass through transient variables and into an API response can hit these limits before the engine does. Ask the team that owns each layer for the current values and test with a payload at your expected maximum.

How DeployOpen scopes and delivers transient variable work

DeployOpen treats transient variables as a design decision with a written scope, not a coding detail to settle during the build. We plan which data stays in the engine, which passes through in memory, and how each path is tested and handed over in your infrastructure.

How we scope

  • Inventory every value passed between tasks, delegates and API calls, marking which must survive a wait state
  • Agree the written scope for transient variable use, including payload size limits and the APIs that return them
  • Record which processes must be safe under restart, retry or failover before any model is changed
  • Confirm the Flowable version and Java baseline the work targets, since the scope depends on it

How we build

  • Model transient and persistent variables explicitly in BPMN and in service task code, not by convention
  • Keep large payloads in external storage with references in process variables, tested end to end
  • Write unit tests that cover wait states, timers and error paths where transient values would be lost
  • Review delegates and expressions for accidental reliance on values that disappear after a save point

How we hand over

  • Deliver a variable map per process listing each variable, its lifetime and its owning delegate
  • Provide test suites that run in your CI pipeline against the deployed process definitions
  • Document the rules for adding new payloads, including size, naming and API response shape
  • Walk your engineers through the design decisions so the team can extend the work without us

How we support

  • Offer ongoing support and upgrades as a retainer when your process estate grows or the Flowable version changes
  • Re-run transient variable tests when processes are redeployed or Flowable is upgraded
  • Review new process changes for variable lifetime issues before they reach production
  • Confirm support terms, response expectations and included testing in the written agreement before work starts

Sources and further reading

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.