Tenant data isolation in multi-tenant Flowable

A shared Flowable engine does not enforce tenant boundaries on its own in every path, so isolation depends on how you assign tenant IDs, filter queries and scope signals. This page explains the decisions and the checks to build.

On this page

Why tenant data isolation in multi-tenant Flowable needs an explicit design

Isolation in a shared Flowable engine is an application responsibility, layered on the engine's tenant ID support. The engine can label the process instances, tasks, variables and other data it creates with a tenant, but it does not decide which tenant a given caller may read or change. Every query, API call, job and signal your platform issues has to carry the tenant context, and every Flowable API you expose has to be checked against that rule. Write this design down before the first customer is onboarded, because retrofitting enforcement across an existing set of models, integrations and reports is far more expensive than building it in at the start.

A shared engine suits a platform where tenants run the same process and case models, per-tenant volume is modest, and you want one database, one deployment and one upgrade cycle. Its main cost is shared failure. The Flowable advanced documentation describes an async executor that runs timers and asynchronous jobs from one thread pool and coordinates nodes through lock owners and lock expiration times in the database, so a single tenant's heavy timer load or failing jobs compete with every other tenant. Separate engines per tenant, each with its own database, reduce that blast radius and simplify per-tenant deletion and data residency, but they multiply deployments, upgrades and monitoring. Flowable can be embedded in Java SE, servlet containers, Spring or used through the REST application, so either pattern is possible and the choice rests on your architecture and your customers' contracts.

DeployOpen plans and implements these controls inside your own cloud accounts, data centers or air-gapped networks. Before you commit to a pattern, confirm which tenants may share a deployment under your contracts and regulators, which Flowable entities and APIs carry tenant IDs in the version you run, and how your team will prove that a query without tenant context is rejected. Flowable 8.0.0, released on February 27, 2026, changed the Spring and Java baseline, so the version decision and the isolation design should be made together.

Which controls keep tenants apart in a shared engine

A shared Flowable engine keeps tenants apart only where every layer carries the tenant identity. The four controls below connect tenant identifiers on stored data, filters on reads, scoping of events that cross process instances, and tenant context for work the engine runs later. Flowable supplies some of these mechanisms, but your application must set the tenant and enforce it on every path.

Tenant IDs on definitions and runtime data

Deployments, process and case definitions, instances, tasks, variables and history can carry a tenant identifier that the engine stores with the record. Your application must set it at deployment and at every start call, and derive it from the authenticated session rather than from request content a caller controls. Confirm in your Flowable version which entities accept a tenant ID, because gaps here cause every later control to fail silently. Check that a tenant cannot deploy a definition that another tenant's start calls will pick up.

Tenant filters on every query

The engine's query APIs return records across all tenants unless your code restricts them. Every task list, instance search, history query and REST call that reads Flowable data needs a tenant condition added in your service layer, not in the client. Build this into a shared data-access component so new endpoints inherit it. Test each query path with two tenants holding records with overlapping names or keys, and confirm that no endpoint, including administrative or reporting ones, bypasses the filter.

Tenant-scoped signals and messages

Signals and messages are broadcast or correlated by name or key, so a message meant for one tenant can reach an instance in another if the names or correlation values overlap. Confirm how your Flowable version scopes signal events and message correlation by tenant. Where scoping is not enforced by the engine, include the tenant identifier in correlation keys and signal names, and validate it in the code that sends the event. Document which external systems can publish events into the engine and which tenant each one may address.

Tenant context in async jobs and timers

The async executor runs timers and asynchronous jobs on a thread pool, coordinated across nodes through lock owners and lock expiration times in the database. Jobs from every tenant share these tables and threads, so a job's tenant must travel with the job, not with the request that created it. Check that delegates, listeners and expressions in async steps read the tenant from the job's data and never from a thread-local user or session. Test retries and lock recovery, because a recovered job must run under the same tenant it started with.

Shared engine or separate engines per tenant

A single Flowable engine serves every tenant. Process definitions, process instances, tasks and other entities carry a tenant identifier, and all tenants share one set of database schemas, one job executor and one deployment. Isolation depends on your application layer, because the engine separates tenants only when your code sets tenant IDs consistently and filters every query, API call and signal by tenant. This model has the lowest operational overhead and the smallest number of moving parts.

  • Isolation strength: Logical only. A single missed tenant filter in a query, API handler or message correlation can expose another tenant's data, so enforcement must be complete across every access path.
  • Operational overhead: One deployment, one monitoring setup and one set of backups. The async executor coordinates lock owners and lock expiration times in the database for all tenants at once.
  • Upgrade coordination: Every tenant moves to a new Flowable version at the same time, so one regression test plan and one maintenance window cover the whole customer base.
  • Database footprint: One schema that grows with every tenant. Index design, history volume and job table growth affect all tenants together, and a noisy tenant can slow everyone else.

Before choosing this model, ask your security team whether logical separation meets your contractual and regulatory obligations, and who signs off on tenant enforcement tests.

How to set up tenant isolation in a Flowable deployment

This sequence moves a shared Flowable engine from one undifferentiated pool of process data to a model where every definition, instance, task, message and job belongs to exactly one tenant. Each step ends with a check so the team can confirm isolation before tenants share the platform.

  1. Define the tenant model and identity mapping

    Decide what a tenant represents in your business, such as a customer, a business unit or an environment, and write it down with its owners. Then map every identity source to tenants: the identity provider groups, the identity management tables or the LDAP identity service you use. Confirm how the engine's identity service is configured in your version, since this decides where tenant membership is stored. Done when every user and service account resolves to one tenant or a documented set of tenants, and an owner has signed off on the model.

  2. Choose a stable tenant ID scheme

    Pick the format for tenant IDs before any data exists. Use opaque, immutable identifiers rather than names, email domains or anything a customer might change. Set rules for length, allowed characters and case, and state that IDs are never reused after a tenant is removed. Keep display names in your own registry, separate from the engine. Done when the scheme is documented, the registry is the single source for tenant IDs, and a test tenant ID created under the rules is accepted by every service that will send it to Flowable.

  3. Assign tenant IDs at deployment and start

    Require a tenant ID when process and case definitions are deployed, and when instances are started. Your deployment pipeline should reject models that arrive without one, so shared definitions do not end up in an unscoped state by accident. Confirm in the Flowable docs for your version which tenant-aware deployment and start calls exist and how queries treat definitions with no tenant. Done when a deployment and a start made for tenant A are visible only when querying under tenant A, and an attempt without a tenant ID fails.

  4. Route all API calls through a tenant-aware layer

    Put one service between callers and the Flowable Java and REST APIs. It resolves the tenant from the authenticated identity, never from a request parameter the caller can change, and passes that tenant into every engine call. It also applies tenant filters to every query and checks that a task or instance belongs to the caller's tenant before completing or reading it. Remove or restrict any path that calls the engine directly. Done when a code search and an endpoint review find no engine call outside the layer, and each query carries a tenant condition.

  5. Scope signals, messages and jobs to tenants

    Include the tenant ID in every message correlation key, signal name or broadcast that can start or move an instance. Make sure timers and asynchronous jobs keep the tenant on the instance they belong to, and check how the async executor reports and retries jobs for each tenant. For external workers and message brokers, decide whether to use separate topics per tenant or a tenant field that the consumer must validate. Done when a message sent with tenant A's correlation data cannot reach a tenant B instance in a test environment, and the broker design is recorded.

  6. Verify with cross-tenant test cases

    Write automated tests that act as a user of tenant A and try to read, complete, start, claim or correlate anything belonging to tenant B. Include direct REST calls, Java API calls, queries, history lookups and scheduled jobs. Each attempt should fail closed, and the test should confirm that no data leaks in error messages or logs. Run the suite on every model change and after each Flowable upgrade. Done when all cross-tenant cases pass in a staging environment, failing cases block release, and the results are stored as evidence for your reviewers.

Configuration choices and when each fits

This table compares the main design choices for separating tenants in a Flowable deployment: tenant ID format, where tenant resolution happens, shared versus per-tenant deployment, and how the async executor and history are handled. Read each row against your tenant count, data sensitivity and operating model, then confirm the listed points with the Flowable documentation before you commit.

DecisionWhen it fitsTrade-offWhat to confirm with the vendor docs
Tenant ID formatOpaque, stable identifiers that never encode customer names, regions or sensitive attributesEvery query, deployment and API call must carry the same value, so a format change later is costly to migrateWhich entities accept a tenant ID on deployment, instance, task and job records, and how tenant IDs are stored and indexed
Tenant resolution in the gatewayEdge routing where each tenant has a distinct host or path and the gateway already authenticates callersTrust moves to the gateway, so any internal route that bypasses it can reach other tenants' dataWhether the engine trusts a tenant value passed by the caller, and which REST endpoints accept tenant parameters
Tenant resolution in the service layerYour own application code builds every engine call and can add tenant filters consistentlyEnforcement depends on every developer and every query path using the helper, which needs tests to stay trueWhich Java and REST API calls accept a tenant ID filter, and which ones return data across tenants by default
Tenant resolution through Flowable identityUsers are modeled in the engine's identity tables or an identity service you override for tenant membershipIdentity services are replaceable, so the mapping from user to tenant becomes custom code you must maintain and testWhether the identity service interface supplies tenant membership to task and candidate checks, and how an overridden identity service is wired in
Shared engine, shared databaseMany small tenants with similar process models and a platform team that runs one upgrade pathOne misconfigured query or signal can affect several tenants, and noisy tenants share job and lock capacityHow the async executor distributes timers and jobs across nodes and whether tenant IDs appear in job records for filtering
Deployment per tenantTenants with strict isolation requirements, separate data residency or independent release schedulesInfrastructure, upgrades and monitoring multiply with the tenant count, and costs recur for each engineDatabase and connection pool sizing per engine, and the supported database types listed in the configuration docs
Async executor settingsLong-running timers or jobs where a slow tenant must not starve othersShared thread pools and lock expiration settings affect every tenant, so tuning changes apply broadlyHow lock owners and lock expiration times are stored, and how recovered jobs are reassigned across nodes
History retention and cleanupTenants with different retention obligations that need separate evidence per tenantDeleting history for one tenant must not remove another tenant's audit trail, so cleanup logic needs tenant-aware rulesWhether history tables carry tenant IDs and how history levels affect the volume of stored data per tenant

Where cross-tenant data leaks happen in practice

Why does a query that leaves out the tenant filter expose other tenants' data?

A query that omits the tenant condition returns rows from every tenant that shares the engine. The engine stores tenant IDs on its entities, but it does not decide which tenant a caller may see unless your code asks it to. Gaps usually sit in custom SQL, reporting jobs, read-only REST wrappers and service code that calls the query API without passing a tenant. The control is a tenant condition on every query your application issues, with the value taken from the authenticated session and never from a request parameter the caller can edit. Inventory every query path, including batch jobs and admin tools, and test each one with two tenants holding data side by side. Confirm with your own code review which paths touch engine tables directly.

Can two tenants safely deploy process definitions with the same key?

Only if the engine keeps them apart by tenant, and your application confirms that for every lookup. Process definition keys are identifiers chosen by the model author, and two tenants can ship a model with the same key. If a start call or a lookup by key omits the tenant, the engine may return the wrong definition or a caller may start another tenant's process. Set the tenant ID on every deployment, then require the tenant in every start, lookup and instance query. Treat a tenant prefix in the key as a naming convention only, and rely on the tenant ID as the control. Ask your team to document which key and tenant pairs exist in production.

How do shared identity groups let one tenant act on another tenant's tasks?

When tenants share candidate groups such as a generic managers or admins group, a user from one tenant can see and claim tasks routed to that group in another tenant. Group IDs are plain strings, so nothing ties a group to one tenant unless your design does. Map each tenant's identity provider groups into tenant-specific group IDs, then assign tasks only to those IDs. Check that task queries filter by both tenant and candidate group, and that complete and claim calls verify the caller's tenant before they act. Confirm with your identity team whether group membership can be granted across tenants, because that single setting can undo every other control.

Can a signal or message reach process instances in another tenant?

Yes, if the event is matched only on a name or correlation key without a tenant condition. Signals are broadcast by name to every subscribed definition, and message correlation matches on business keys or correlation values that different tenants may reuse. Scope every signal and message to a tenant by including the tenant ID in the event name, the correlation key or both. Have the API that raises events set the tenant from the caller's session, and reject events that arrive without one. Keep a list of all event names in use, since a generic name such as orderUpdated is a common source of cross-tenant delivery. Test with matching keys in two tenants and confirm that only the intended instance resumes.

Why do history and audit reads need tenant checks as well as runtime queries?

Historic tables and audit logs hold the same tenant data as runtime tables, and they often outlive the running instance. A reporting screen or support tool that reads history without a tenant condition can expose completed cases, variables and comments from other tenants. Historic variables may hold personal data, so the exposure extends beyond process status. Apply the tenant filter to every history query, audit export and log view, and restrict who can run them. Check whether support staff use shared dashboards that query across tenants, and whether retention jobs delete by tenant. Confirm which history levels you enable, because more detail means more data to protect.

Does the engine enforce tenant isolation for me, or must my application do it?

Your application must enforce it. Flowable provides tenant IDs on its entities and lets you filter queries by them, but the engine does not decide which tenant each of your users may reach. Your API layer must derive the tenant from the verified identity, pass it to every engine call and reject requests where the tenant does not match the resource. Treat the engine's tenant fields as the storage model and your authorization layer as the policy. Ask your team to write tests that attempt cross-tenant reads and writes through every endpoint, including the REST API and any custom services. Review this design with your security team before the first tenant onboards.

Security and operational considerations for shared tenants

Tenant IDs and query filters only protect data if the surrounding controls hold. The cards below cover the API layer, testing, logs, backups and upgrades, the places where a shared engine most often leaks or mixes tenant data. Each one needs an owner and a check before go-live.

API layer enforcement

Flowable's REST and Java APIs authorize callers against engine privileges and identity data, but they do not know which tenant a business user belongs to. Your API layer must resolve the tenant from the authenticated identity, reject any request that names another tenant's process instance, task or deployment, and pass the tenant ID into every engine call. Confirm that no endpoint accepts a tenant ID from the client body without checking it against the caller. Review the Flowable REST docs to see which endpoints you expose at all.

Cross-tenant test fixtures

Automated tests should create at least two tenants with overlapping user names, process keys and task names, then attempt reads, completions, signals and deletions across the boundary. Illustrative case: a tester deploys the same process definition under two tenant IDs and confirms that a message correlated in one tenant never starts or advances an instance in the other. Run these tests on every change to queries, services or API filters so that a missed filter fails the build rather than a production audit.

Tenant identifiers in logs and audit data

Engine history, job logs and application logs can record tenant IDs, process variables and user names, so the logs themselves become tenant data. Confirm which history and audit records your configuration writes, who can query them across tenants, and how long each store keeps them. Keep tenant ID as a structured field in your log pipeline so that a tenant's logs can be exported or purged on request without a full search.

Per-tenant backup and restore

Flowable keeps all tenants in one set of database tables, so a backup is normally a whole-database snapshot and cannot restore one tenant without touching the others. Decide whether you need tenant-level export, and test a restore into a scratch environment that you then compare against the source for one tenant. Also confirm how in-flight async jobs and timers behave after a restore, because the async executor relies on lock owners and expiry times stored in the database.

Upgrade regression testing

Major upgrades change the Java, Spring and Jakarta baseline, which can alter query generation, serialization and default behavior. Flowable 8.0.0 moved to Spring Framework 7 and Spring Boot 4 and made Jackson 3 the default JSON library, so custom queries, tenant-aware listeners and serialized variables need re-testing. Run the cross-tenant suite against the new version before upgrading any shared environment, and keep the previous release available for rollback.

Operator and administrator access

Engine administrators, database operators and support staff often see every tenant by design. Limit who holds the admin role, the database credentials and the actuator endpoint, and record every cross-tenant action in your audit trail. Ask your team to document which operator roles can read raw tables, since a direct SQL query bypasses every application filter.

Questions buyers ask about tenant isolation in Flowable

How much effort does a shared Flowable engine with tenant isolation take?

Effort depends mainly on how many paths in your application touch process data. The engine stores tenant identifiers on runtime, history and task data, but your application must set, check and filter them on every route into the engine. Those routes include REST calls, scheduled jobs, signals, messages and reporting queries. A team with a small set of entry points and a clear identity model can limit the work to a few modules. A platform with many services, custom delegates and shared reporting jobs has more surfaces to review, test and document, so the work grows with each one. Ask for a list of every entry point before agreeing any estimate.

What drives the cost of tenant isolation work up?

Cost is mostly people time, and the written scope shows who is paid for each part. These factors raise it:

  • The number of REST endpoints, signal handlers and custom delegates that read or write tenant data
  • How many identity sources feed tenant membership, such as the Flowable identity tables, LDAP or an external identity provider
  • The volume and sensitivity of data per tenant, which sets how thorough the negative tests must be
  • The state of existing process models, especially those without tenant-aware variables

The design and build are mostly one-time costs. Recurring effort appears when new tenants, models or integrations must be checked against the isolation rules. Ask for a quote that separates design, build, testing and handover, and that states what each later change will cost.

Can our own team build tenant isolation in Flowable without a partner?

Yes, a team with Java, Spring and Flowable experience can build it, and the Flowable documentation covers the engine side of multi-tenant data. The harder part is usually the application: finding every path into the engine, deciding where tenant identity comes from, and proving that no path crosses a boundary. Internal teams often underestimate the negative testing and the review of jobs and queries that bypass the normal code path. Check the tenant features and their behavior in the documentation for your exact Flowable version before you design around them. A fixed-scope review of your design or test plan is one way to get an outside check without handing over the whole build.

How long does verification of tenant isolation take?

No duration can be given here because it depends on your tenant count, entry points and test data. Verification has three layers. The first is automated tests that create at least two tenants and confirm that every read and write stays inside its tenant. The second is negative tests that try cross-tenant access through each REST endpoint, signal and message. The third is a review of queries, scheduled jobs and reporting code that bypasses the normal path. Each layer needs test data prepared in advance. Ask for the verification plan and its exit criteria in the written scope before you agree a timeline. Security testing of your APIs can run alongside this work as a separately scoped service.

What does the isolation work need from our team before it starts?

The work needs three inputs before design begins. The first is your identity model: how users, groups and roles map to tenants, and whether identities live in Flowable's identity tables, LDAP or an external identity provider. The second is the tenant list, with the data class and business owner for each tenant. The third is test data: a non-production environment with at least two tenants and process models that resemble production. You should also provide the process models, custom delegates, integration list and any reporting queries, because those are where cross-tenant leaks usually hide. Confirm each input in writing so that the scope reflects what your environment really contains.

Does a shared Flowable engine need a separate database for each tenant?

Not necessarily. A shared design keeps one engine and one database, with tenant identifiers on entities and enforcement in the application. Separate databases or schemas per tenant give stronger separation for some data, but they multiply the operational work. Deployments, upgrades, the async executor, backups and monitoring must be handled for each database. The right choice depends on your tenant count, the data classes involved and what your regulators and customers expect. Confirm the requirement with your data protection lead before you choose, because changing the model after go-live is expensive.

Where does tenant isolation most often fail in Flowable applications?

Tenant isolation most often fails at the edges of the engine rather than in the core process logic. The common failure points are:

  • REST calls that take a tenant identifier from client input without checking it against the caller's rights
  • Signals and messages broadcast without a tenant scope, so one tenant's event starts another tenant's process
  • Timers and asynchronous jobs that run without the tenant context of the process that created them
  • Custom delegates and expressions that read variables belonging to another tenant
  • Reporting or administrative queries that run direct SQL and skip the tenant filter

Each point should have a test that tries to cross the boundary and fails.

Does tenant isolation in Flowable satisfy a compliance requirement by itself?

No. Tenant isolation is one control among several. Auditors test whether access is restricted, whether changes are logged, and whether you can show evidence that the controls work over time. Tenant tests, access reviews, audit history and change records all support that evidence. DeployOpen prepares systems, controls and evidence for compliance assessments, but it does not issue audit reports, attestations or certifications. Independent auditors and certification bodies do that work. Ask your auditor early which tenant separation evidence they will sample, so the test plan and logs produce it.

How DeployOpen scopes and delivers tenant isolation work

DeployOpen agrees the scope of tenant isolation work in writing before any build starts, because the boundary between engine configuration and application code decides who owns each control. A typical engagement covers the tenant ID model on Flowable entities, the query and signal paths your application uses, the enforcement layer in front of the engine, and the cross-tenant tests that prove the boundaries hold. Each of these items is listed in the statement of work with its deliverables and acceptance criteria, so you can see which controls DeployOpen builds, which ones your own team keeps, and which ones depend on your identity provider or your database. Most engagements are fixed-scope, and any change to tenant count, data residency or integration points is handled as a written change to that scope.

DeployOpen implements and hardens the Flowable engines inside your own cloud accounts, data centers or air-gapped networks, so tenant data never leaves infrastructure you control. Delivery includes configuration of the engine and REST layer, the enforcement code, deployment through your pipeline, and security testing that includes cross-tenant tests against a staging copy of your environment. Those tests attempt to read, complete, start and signal work across tenant boundaries using realistic credentials for each tenant. Results are reported with reproduction steps and fixes, and retests are part of the agreed scope. Ongoing support, upgrades and continuous testing are available as retainers, which matter because Flowable releases and your tenant model both change over time.

DeployOpen prepares systems, configuration, access records and test evidence for compliance assessments, but it does not issue audit reports, attestations or certifications. Independent auditors and certification bodies make those determinations, so ask your assessor early which evidence they expect for tenant separation, such as access reviews, test results and change records. Before you sign, confirm with your compliance lead which controls must be evidenced, who holds the evidence after handover, and how it will be kept current when the engine is upgraded. A quote follows from the written scope, so the questions above should be settled before the statement of work is drafted.

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.