Call activities vs embedded subprocesses in Flowable: when each fits
Use an embedded subprocess when the steps belong to one business case, need the parent process's variables and lifecycle, and make no sense outside that parent. Use a call activity when the called process is reusable, owned by another team, or needs its own deployment and versioning. The difference is runtime behavior. An embedded subprocess runs inside the parent's process instance, so its tokens, variables and boundary events sit in the same instance. A call activity starts a separate process instance of a referenced process definition, and the parent waits for that instance to end unless the model says otherwise. This page covers the Flowable engine's modeling choices, not a general BPMN primer.
A model usually outgrows its diagram before it outgrows the engine. Typical signs are one diagram with dozens of tasks, the same approval branch copied into several processes, and reviewers who cannot trace where a variable is set. Before you split anything, check four things: whether the block changes on a different release cycle from the parent, whether another process reuses it, whether it needs its own instance ID and history for audit, and whether a different team owns it. If none of these apply, an embedded subprocess is usually easier to review. For a call activity, confirm how your Flowable version resolves the calledElement reference and which definition version is bound when the parent starts the child, because that binding decides which logic runs.
The main risks are variable mapping, version drift and completion timing. A call activity hides the called process's internal variables unless you map them explicitly in and out, so define each mapping and test that the parent sees the values it expects. Version drift occurs when a child definition changes while parents still expect the old contract, so agree on the interface and the deployment order before you release. Decide whether the parent waits synchronously or continues asynchronously, and confirm how async completion behaves in your engine version using the Flowable advanced documentation. Test these paths with long-running children and failed jobs before production.
How each construct runs inside the Flowable engine
An embedded subprocess is part of the parent process definition. When the token reaches it, the engine creates a scope inside the parent instance, so the subprocess shares the parent's process instance, its variables and its transaction context. Work inside it is committed along with the parent unless you add asynchronous boundaries. The subprocess is drawn and deployed as one unit with the parent, so the parent and the subprocess always change together.
- Shared variables: Subprocess activities read and write the parent's variables by default, and local variables stay visible only inside the subprocess scope.
- Single deployment: The subprocess has no separate definition, so a change to it creates a new version of the whole parent model.
- Parent waits implicitly: The parent token stays inside the subprocess until its end event is reached, with no separate instance to track.
- Shared transaction context: Failures inside the subprocess roll back to the last committed point of the parent unless async continuations split the work.
- Limited reuse: Another model can only reuse it by copying the diagram, which leaves copies to drift apart.
Before relying on this construct, confirm with your engineers which variables the subprocess needs and where asynchronous boundaries will sit.
A call activity starts a separate process instance of another process definition and waits for it to finish. The called process has its own process instance, its own variables and its own history. Variables cross the boundary only through explicit input and output mappings on the call activity, so the parent controls what it passes in and what it receives back. The called definition is referenced by key or by ID, and it can be deployed separately from the parent.
- Separate ownership: A team can own and version the called process independently of every parent that uses it.
- Explicit data contract: Input and output mappings define the interface, which makes changes to variables visible in review.
- Separate instance and history: Each called instance has its own history records, which helps when a sub-process needs its own audit trail.
- Parent waits for completion: The parent token waits at the call activity until the child instance ends, unless the call is completed asynchronously.
- Reuse across models: Several parent processes can call the same definition without copying its diagram.
Confirm how your deployment pipeline resolves the called definition, whether by key from the same deployment or by a specific ID, because that choice drives versioning.
The construct you choose also decides who can change what and how often. An embedded subprocess belongs to the parent's model and release cycle, so its owners are the parent's owners. A call activity points to a process that can have its own owners, release schedule and tests. This matters when several business areas share a common step, such as identity verification or document generation, and each wants to change it on its own timetable.
- Model owner: Embedded logic is reviewed with the parent diagram in one change set.
- Shared service owner: A called process can be maintained as a service with its own review and release process.
- Copy risk: Repeating an embedded subprocess across models multiplies the number of versions you must test and keep in step.
- Dependency visibility: Call activities create explicit dependencies that appear in the model, which helps impact analysis.
- Governance cost: Separate processes need agreed contracts for variables and error behavior, which takes coordination.
Ask your team who will approve changes to shared steps and how dependencies will be tracked in your release process.
Both constructs make the parent wait, but the mechanics differ in what the engine tracks and what can go wrong while waiting. With an embedded subprocess, the parent's execution tree holds the waiting token and the subprocess work. With a call activity, the parent waits on a separate instance, so a stall in the child is visible as a running child instance rather than as a deep token inside the parent. Completion of the child returns control to the parent through the call activity's outgoing flow.
- Token location: Embedded waits show as tokens inside the parent scope, while call activity waits show as a linked child instance.
- Output timing: Output mappings apply when the child completes, so parent variables do not change earlier.
- Cancellation: Terminating the parent affects the embedded scope directly, while a called instance has to be handled as its own process instance.
- Asynchronous completion: A called process can be completed by a later event or external signal, which changes how long the parent waits.
- Monitoring: Child instances need their own monitoring queries and alerts.
Check how your operations team will find and act on stalled child instances before you choose call activities for long-running work.
The choice is easiest to make when you list the constraints first: who changes the logic, how many models need it, whether it needs its own history and how long it can wait. Build a small illustrative model with both constructs, then test the data flow, the failure path and the deployment behavior. Testing one parent with an embedded subprocess and one with a call activity shows the operational differences in your own environment before you commit to a pattern across many processes.
- Reuse count: Use a call activity when several parents need the same logic, and an embedded subprocess when only one parent does.
- Data flow: Test that every input and output mapping produces the variables the parent expects.
- Failure path: Inject an error inside the child and in the embedded scope, then compare how each one surfaces to the parent.
- Deployment behavior: Deploy a new version of the called process and confirm which version the parent calls.
- History needs: Confirm the history records your auditors and analysts require exist for each construct.
Check these results with your engineers and your operations team before you set a modeling standard for the wider program.
Configuration options for calling and nesting processes
This table compares the ways a Flowable model can run work outside its main flow, from an embedded subprocess to a call activity that targets a process by ID or within the same deployment. Read each row for the situation it fits and the cost it carries, then confirm attribute names against the Flowable BPMN documentation before you standardize on a pattern.
| Option | When it fits | Main trade-off |
|---|---|---|
| Embedded subprocess | Steps that belong to one business transaction and should share the parent's lifecycle, timers and variable scope | Diagram grows large and cannot be reused by other processes without copying the logic |
| Call activity by process ID | A separately owned process that several parents reuse, deployed as its own definition | Parent depends on the called definition existing at runtime, so deployment order and ownership must be managed |
| Call activity in the same deployment | Parent and child are versioned and released together as one set of process files | Changes to the child ship with every parent release, which can slow independent change |
| Variable mapping in and out | Passing only the inputs the child needs and returning only its results to the parent | Unmapped variables are not visible to the child, so missing mappings surface as runtime errors or empty values |
| Async continuation on the call activity | Long-running children or steps that should commit in their own transaction and retry on failure | Adds job execution and latency, and the parent waits in a state that operations teams must monitor |
| Called process version selection | Parent should follow a fixed or latest version of the child when a new definition is deployed | Latest-version binding can change behavior of running parents without a deliberate release, so confirm the default in your Flowable version |
How to structure a large model with call activities
This sequence turns a monolithic Flowable model into a parent process that calls reusable child processes with clear variable contracts and a known versioning behavior. Each step ends with a check you can run before the next one starts.
Set process boundaries by business ownership
Before drawing anything, list the stages of the end-to-end process and assign each one to the team that owns its decisions and outcomes. Stages owned by one team with a stable interface are candidates for a child process, while steps that only exist to serve the parent flow usually stay as an embedded subprocess. Write down, for each candidate, its inputs, its outputs and the people who approve changes to it. You are done when every candidate has a named owner and the parent process reads as a short sequence of business stages.
Model and deploy the child process
Model the child process as its own BPMN file with a single, documented start point and clearly defined end states. Give it a process definition key that the parent will reference, and keep its variables limited to the contract you agreed with the owning team. Deploy it to the same engine or to a target environment you control, then confirm the deployment appears in the repository service with the expected key and version. If the child cannot be found after deployment, stop here, because every later step depends on that lookup.
Reference the child from the parent call activity
In the parent model, add a call activity and point it at the child by process definition key, or by ID if your team pins specific versions. Choose whether the call uses the latest deployed version or a fixed version, and record that choice in the model documentation. Confirm the parent deploys without a validation error and that starting an instance creates a child instance when execution reaches the call activity. Check the runtime service for the parent and child instance IDs to confirm the link.
Map variables in and out explicitly
Define the input mappings that copy parent variables into the child, and the output mappings that copy child results back to the parent. Keep mappings narrow so the child cannot read or overwrite unrelated parent data, and avoid relying on implicit variable sharing. Use names that match the contract from the first step. You are done when a test run shows the expected input variables present in the child and the agreed output variables visible to the parent after the child completes.
Decide and test the versioning behavior
Decide how the parent should behave when the child changes: whether running parent instances keep the child version they started with, and whether new instances pick up the latest deployment. Test both situations by deploying a second child version and starting new parent instances, then checking which child version each instance uses. Involve the team that owns the child process, because a silent version change can alter business results. Record the rule in the model documentation so operations knows what a redeployment will affect.
Handle asynchronous completion where the child is long-running
If the child waits on people, timers or external messages, decide whether the call activity should wait synchronously or whether the child's completion should be handled asynchronously. Confirm with the engine documentation how async continuations and the async executor behave in your version before relying on them, and test that the parent resumes after the child finishes, including after a restart. Check that no parent instance remains waiting after its child has ended.
Test the parent with the child deployed
Run end-to-end tests of the parent with the real child deployed, not a stub, covering the happy path, each child end state and at least one failure path. Verify that output variables reach the parent, that gateways downstream of the call make the right choices, and that the history shows both parent and child activities in order. Repeat the test after any redeployment of the child. The sequence is complete when these tests pass in an environment that matches production deployment practice.
Document the contract and ownership for operations
Write a short contract for each child process listing its key, its input and output variables, its end states, its versioning rule and its owning team. Store it alongside the BPMN files so that changes to either side go through the same review. Hand the contract to operations and the owning teams, and confirm they can find a child instance from a parent instance during an incident. The step closes when every call activity in the model has a matching contract entry.
Passing variables in and out and versioning called processes
Variable mapping between a parent and a called process is the first design decision to settle, because it determines what the child can see and what the parent gets back. In a call activity, input mappings copy values from the parent execution into the child process instance when it starts, and output mappings copy selected values back when the child completes. Keep the mapping list explicit and short: map only the identifiers the child needs, give each one a name that states its meaning, and avoid mapping everything by default. Confirm the exact mapping element names and whether a mapping can be expressed as an expression against your Flowable release in the Flowable BPMN docs, since mapping syntax has changed between major versions and must match the version you deploy.
Large or unstructured variables deserve special care. Every mapped value is serialized into the database and copied at each call boundary, so a parent that passes a full case document, a list of thousands of records or an opaque JSON blob multiplies storage and slows every instance that carries it. Pass a reference such as an identifier, and let the called process load detail through a service task when it needs it. Also check how your team stores object values in variables and which serializer the engine uses in your deployment, because a class change between releases can make stored values unreadable on resume. Ask whether your variable policy is written down before the first model is built, not after a support ticket.
Versioning is the risk that surfaces after go-live. When a called process is redeployed as a new version while parent instances are still waiting on it, the question is which definition a new call resolves to and what happens to instances already running on the old definition. Decide whether the call activity should reference a specific process definition ID, which keeps behavior fixed but requires a deliberate migration, or resolve the latest version by key, which picks up changes automatically but can change behavior mid-flight. Treat that choice as something to confirm against the Flowable docs for your release, then tie it to the migration guidance in the Flowable features group, and test a parent instance started before the redeployment as part of your release checklist.
Security and operational risks in multi-process models
Once a parent process calls another process, data, authorization and failure handling cross a boundary that a single diagram does not show. The cards below cover the risks that most often surface only after go-live, and the checks to run before a call activity reaches production.
Sensitive data passed between processes
Call activities copy variables into the child process and copy results back out, so a field that was harmless in the parent can end up in the child's runtime data and history. Map only the variables each called process needs, and review which of them are stored in the database and visible through the history and REST APIs. Confirm how your Flowable version handles variable scope and history retention for mapped variables before you choose which data may cross the boundary.
Authorization left to the application
Starting a called process by its ID does not by itself check whether the user or service initiating the call may run it. The Flowable engine leaves most authorization decisions to your application, so a parent process that can reach any deployed definition can also start definitions it was never meant to use. Decide which process IDs a given caller may invoke, enforce that check in your service layer or REST gateway, and test it with a user who lacks the right.
Failed child jobs stalling the parent
A called process runs its own jobs, and an asynchronous step that fails there leaves the parent waiting at the call activity until the job is retried or moved to the deadletter state. Operators who watch only the parent instance can miss a stalled child. Check how failed jobs in child instances surface in your monitoring, set retry behavior deliberately for jobs that call external systems, and document who acts on a deadletter job.
Actuator exposure for child instances
In Spring Boot deployments, the Flowable actuator endpoint at /actuator/flowable reports on running processes, which can include child instances started from call activities. Exposing that endpoint without authentication or network restrictions gives anyone with access a view of process state and volume. Confirm which actuator endpoints your deployment exposes, restrict them to your monitoring network, and verify that the output you alert on includes child instances.
Version drift between parent and child
A call activity can reference a called process by ID, and a later deployment of that process may change the behavior the parent expects. Running parent instances and new calls can then hit different versions of the same child process. Record which called version each parent instance used, and plan a deployment order that keeps variable contracts stable for instances already in flight.
Questions teams ask before modeling large Flowable processes
How much effort does it take to restructure an existing model into call activities?
The effort depends mostly on how many subprocesses the model already has, how many variables cross their boundaries, and how many other models depend on them. Restructuring is usually a refactoring exercise: each embedded subprocess becomes a separate deployed process with its own input and output mappings, and the parent model calls it by key or ID. Teams should inventory every subprocess, list the variables it reads and writes, and identify which ones are reused elsewhere. Ask any partner for a written estimate that breaks the work into inventory, model split, mapping, test and rollout, because each step has different drivers.
Can our team restructure the models without outside help?
A team with working knowledge of BPMN 2.0 and the Flowable engine can usually do the restructuring in-house, especially for a small number of processes. Outside help tends to add value where the model is large, where variable contracts are unclear, or where the team lacks time to test every path. Whichever route you choose, agree on the decomposition rules first, such as which subprocesses stay embedded because they share transaction scope or timers with the parent. Ask a partner to state in writing which parts of the work it will perform and which parts your staff will own.
What does the work need from process owners and developers?
Process owners need to confirm the business boundaries of each reusable step, approve the variable contract between parent and child, and agree on acceptance tests that reflect real cases. Developers need to define input and output mappings, handle service tasks and delegates inside the called process, and keep the deployment pipeline consistent across both definitions. Plan a short working session where process owners sign off on the decomposition before developers change any diagram. Without that sign-off, teams often split models along technical lines and then have to split them again.
How do version changes affect running instances of a called process?
A running parent instance keeps the called process definition it started with unless the call is resolved again, so version handling needs an explicit decision. Calls by ID pin a specific definition, while calls by key can resolve to the latest deployed version when a new call starts. Confirm the exact resolution behavior for your Flowable version in the configuration and process documentation, and test a version change against instances that are already waiting. Plan a rule for when old instances finish on old definitions and when a migration of running instances is needed.
Does the Flowable version we choose change the work?
Yes. Flowable 8.0.0 was released on February 27, 2026, following 7.2.0 on August 21, 2025 and 7.1.0 on October 7, 2024. The 8.0.0 release notes describe an upgrade to Spring Framework 7 and Spring Boot 4 with no backward compatibility for Spring Boot 3, so a team on Spring Boot 3 will need a platform upgrade before or alongside the model work. Confirm the target version and its baseline before estimating restructuring effort, because the two changes compound.
What drives the cost of this work up or down?
Cost rises with the number of subprocesses to split, the number of variables crossing each boundary, the number of parallel versions in production, and the depth of testing needed for long-running paths such as timers and boundary events. Cost falls when the model is already modular, when the variable contracts are documented, and when the team reuses a test harness. Recurring costs include maintaining called-process contracts and retesting when a dependent process changes. Ask any quote to separate one-time refactoring from ongoing support, and to state what is included for a platform upgrade.
When should a subprocess stay embedded instead of becoming a call activity?
Keep a subprocess embedded when it needs to share the parent's transaction scope, its timers, boundary events, or its variables without a formal contract. Move it to a call activity when several models reuse the same logic, when it has its own lifecycle and ownership, or when it needs independent versioning. The Flowable advanced documentation explains how the async executor handles timers and asynchronous jobs across nodes, which matters when a long-running child waits on a timer. Document the rule you apply so reviewers can check each split the same way.
How DeployOpen scopes Flowable modeling work
DeployOpen plans and implements Flowable models inside your own infrastructure, whether that is your cloud accounts, your data centers or an air-gapped network. For a call activity versus embedded subprocess question, that means the work covers the process definitions themselves, the decision on how each subprocess boundary is drawn, the variable contracts that cross it, and the deployment pipeline that ships called and calling definitions together. Engagements are typically fixed-scope, so the models in scope, the number of process and subprocess definitions, the called processes that must be reused across applications, and the integrations each one touches are agreed in writing before build work starts.
Before you sign, ask for the written scope to name the specific deliverables: the decomposition diagram, the input and output variable map for every call activity, the chosen referencing method (same deployment or by process ID), the versioning rule for called processes, and the test cases that prove async completion behaves as designed. Also confirm which items are your responsibility, such as access to your Git repository, deployment environments and database instances, because delays on those inputs are the most common reason a fixed scope moves. Any timeline should come from that written scope, not from an estimate offered in a sales conversation. After go-live, ongoing support, Flowable version upgrades and continuous testing can be covered by a retainer. Ask whether a retainer would include review of new or changed called processes, since a version change to a shared subprocess affects every parent that calls it. The retainer terms, response expectations and what is excluded should be written down the same way as the original scope, so you can judge the recurring cost against the work your own team would otherwise absorb.
How DeployOpen delivers Flowable process architecture
DeployOpen plans, implements, documents and supports Flowable engines inside your own infrastructure, including the decision between embedded subprocesses and call activities. We agree the process boundaries, variable contracts and deployment approach in writing before build work starts, so the structure of your models is settled before the first large diagram is drawn.
How we scope
- Map which process fragments stay embedded and which become reusable called processes, with the reason for each boundary
- Define the variable contract for every call activity, listing inputs, outputs and types agreed with the process owners
- Agree in writing how called processes are referenced, either from the same deployment or by process definition ID, and how versions are pinned
- Confirm the async completion points and the transaction boundaries your operations team needs to monitor
How we build
- Model parent and child processes in BPMN 2.0 with the Flowable Designer or your preferred modeling tool, keeping diagrams readable at review
- Implement input and output mappings so called processes receive only the variables they need and return results in a defined shape
- Write tests that start parent processes, complete called processes and check variable propagation, including the asynchronous completion path
- Configure the deployment pipeline so called process definitions are deployed in a known order and tagged with version identifiers
How we hand over
- Deliver a written architecture record covering process boundaries, variable contracts, versioning rules and the reasons behind them
- Document how to add a new called process, retire an old version and check which parent processes depend on it
- Walk your engineers through the test suite, the deployment order and the monitoring points for running instances
- Provide runbooks for stuck call activities, failed child jobs and reruns of asynchronous completion steps
How we support
- Review new models for process depth, variable sprawl and reuse before they reach production
- Support upgrades of the Flowable engine and changes to shared called processes through a planned release process
- Ongoing support, upgrades and continuous testing are available as a retainer, scoped in writing with your team
- Quotes follow from the written scope, so ask for the effort drivers, the test coverage and the handover items to be listed separately

