When the Flowable UUID ID generator becomes the right choice
Consider the StrongUuidGenerator when your Flowable engine sees sustained concurrent process starts, parallel branches or API writes that wait on ID allocation from the database. The default database ID block generator is the simpler option to run, and the switch is worth testing only when your own data shows that ID allocation is a point of contention. Look first at whether the slowdown appears during bursts of new instances or at joins where parallel branches write at the same moment, since those are the patterns where a different generator can change the outcome.
The switch is both a configuration decision and a dependency decision. You change the generator in the engine configuration and add the library that the UUID implementation needs, so the build, the container image and the deployment pipeline all change with it. The class name, the dependency coordinates and the default behavior depend on the Flowable version you run, so confirm them against the Flowable configuration documentation and the release notes for that exact version before you change anything. Also confirm what the block size setting (idBlockSize) does in the database generator, because tuning it is the first lever many teams pull before they consider a different generator.
Treat the change as a hypothesis that a load test must confirm. Run the same workload against both generators, using realistic process start rates, parallel branch counts and API write patterns from your own production logs, and compare throughput, response times, database lock waits and the number of optimistic locking exceptions. Record the database load on the ID allocation path as well. Also check the downstream effects: UUID identifiers are longer and less ordered than sequential numbers, so confirm that reporting queries, indexes, archiving jobs and any system that stores Flowable IDs can handle them before you commit to the change.
Choosing between the database ID block and StrongUuidGenerator
This table compares the default database ID block generator, its block size setting, StrongUuidGenerator, and a custom generator built on the engine's ID generator interface. Read each row for how IDs are allocated, which load pattern it suits, and what it adds to operations. Confirm setting names and dependencies in the docs for your Flowable version before you change anything.
| Option | How IDs are allocated | Load pattern it suits | What it adds to operations |
|---|---|---|---|
| Default database ID block | Each node reserves a block of IDs from a database row, then hands them out from memory. | Single node or moderate concurrency, where ID requests are infrequent. | No extra dependency. Block refills add database round trips and can contend during bursts. |
| Tuning idBlockSize | Sets how many IDs a node reserves per refill. Unused IDs in a block are lost on restart. | Many nodes creating instances in bursts, where refill contention shows up in the database. | Trades fewer refills against larger gaps in IDs. Confirm the setting name and default for your version. |
| StrongUuidGenerator | The application generates UUID-based IDs locally, so no shared database row is needed per ID. | High concurrency across many nodes, where ID contention on the database is the bottleneck. | Requires an extra UUID library on the classpath. Check the artifact name and compatibility in the docs. |
| Custom generator on the ID generator interface | Your code implements the engine's generator interface and controls how each ID is produced. | Specific needs, such as a required ID format, that the built-in options cannot meet. | You own collision safety, testing and any changes needed when upgrading Flowable. |
| Index and storage effects | Random UUID values spread inserts across index pages, unlike sequential block-based values. | Large history and runtime tables where insert patterns affect database performance. | Measure insert latency and index size on your own database before and after switching. |
Failure modes to rule out before switching generators
Switching to the StrongUuidGenerator only helps when ID allocation is the bottleneck. The symptoms below look similar from the application side, so each card names the first thing to check and the other causes to exclude before changing the generator.
Database waits on ID allocation
The default generator reserves blocks of IDs by reading and updating a row in the ACT_GE_PROPERTY table, and concurrent transactions queue on that row. Check the database wait events during peak starts for lock or row-update waits on that table. If the waits sit on history, job or variable tables instead, the generator is not the cause and the switch will not help.
Optimistic locking errors on concurrent starts
Under heavy parallel process starts, you may see FlowableOptimisticLockingException or duplicate-key errors tied to new instance or task IDs. Before blaming ID allocation, confirm the failing statements are inserts into engine tables and not updates to the same process instance. Shared-instance updates usually come from API callers or parallel joins, which are covered by exclusive job and locking analysis.
Throughput that flattens as nodes are added
If adding engine nodes does not raise instance starts per second, a single hot row or serialized lock may be limiting all nodes. Compare throughput at one node and at two or three nodes under the same load profile. A flat curve with rising wait time on the ID property row points to allocation. A flat curve with busy async executor threads points to job acquisition instead.
Large history and job tables skewing results
Growing history, variable and job tables increase write volume on every instance and can look like ID contention in aggregate timings. Check row counts in the history and job tables and the history level in use before testing the generator. Clean up or reduce history retention first, then rerun the load test so the results reflect the generator alone.
Async executor saturation
When the async executor thread pool or job queue is full, jobs wait and load appears to stall at the engine. Check the executor's queue depth, active thread count and lock expiry activity in logs before changing ID settings. Saturation caused by undersized pools is solved by tuning the executor, and a generator change would leave it in place.
Workload shape hiding the real bottleneck
Bursty test traffic, many instances started from one client, or a test database that is smaller than production can all concentrate contention. Reproduce the production arrival pattern, with the same number of concurrent starts and node count, before drawing conclusions. A result that depends on an unrealistic burst pattern should be treated as a test artifact until confirmed.
Setup sequence for switching and testing both generators
This sequence moves a Flowable engine from the default database ID block generator to the StrongUuidGenerator only after a same-conditions comparison shows the change helps. Each step ends with a check, and the final step restores the previous setup if the results do not support the switch.
Record the current generator and block size
The platform engineer records the ID generator setting, the idBlockSize value, the Flowable, Spring Boot and Java versions, the database type and the number of engine nodes. Read the values from the deployed configuration of each node, not only from the source repository, because overrides in environment variables or Spring properties can differ. Check the Flowable configuration docs for the keys that apply to your engine version. The step is done when a baseline record sits in the change ticket and every node's values match it.
Reproduce contention in non-production
The performance or platform team builds a load profile that matches production peaks, including concurrent process starts, parallel branches that join, and the number of engine nodes. Run it against the current generator in a non-production environment with the same database engine and version as production. Capture ID-related contention signals such as database waits on the ID block table, optimistic locking exceptions and job latency. The step is done when the baseline run is saved with its parameters. If the current setup shows no contention under this profile, record that result and stop before changing the generator.
Add the matching StrongUuidGenerator dependency
The developer adds the StrongUuidGenerator dependency that matches the Flowable release and Spring stack in use, and confirms the artifact coordinates in the Flowable documentation for that release rather than copying them from older examples. For Flowable 8.0.0, the release notes state an upgrade to Spring Framework 7 and Spring Boot 4 with no backward compatibility for Spring Boot 3, so mixed baselines will fail. Check the dependency tree for a single resolved version of the engine and no conflicting Jackson or Spring artifacts. The step is done when the build passes and the tree is clean.
Configure the generator behind a switch
The developer sets the generator in the engine configuration and keeps idBlockSize at its recorded value so that the only variable between runs is the generator. Expose the choice as a single property or deployment profile so the same build can run with either setting. Check that application startup logs or the configuration endpoint report the active generator class on every node. Also start one process instance and confirm that IDs are generated and the process completes. The step is done when both settings can be selected without a code change.
Deploy both settings to a staging cluster
The platform team deploys the same build to a staging cluster that matches the production node count, database type and connection pool sizes. Deploy the two settings as separate environments or profiles, and keep the other configuration identical. Confirm each node reports the expected generator and that no node is running a different build version. Any mismatch between nodes blocks the test until it is fixed, because a mixed cluster would invalidate the comparison. The step is done when a checklist of node-level settings is signed off for each environment.
Run the same load profile against both settings
The performance team runs the identical load profile, with the same data volume and job mix, against each setting, and alternates the order of runs to reduce the effect of database cache state. Record throughput, latency, error counts, optimistic locking exceptions, database contention on the ID tables and async job backlog for each run. Repeat runs enough times to see whether differences exceed normal variation. Check that the two result sets share the same parameters before comparing them. The step is done when a side-by-side comparison exists and the team agrees on whether the change is justified.
Roll back if results do not support the switch
If the comparison does not show a clear benefit, or the new setting introduces errors, the platform team restores the recorded generator setting, the previous dependency version and the recorded idBlockSize, then redeploys. Confirm from startup logs that every node reports the original generator and run the smoke test from the earlier steps. Also confirm that downstream systems accept any IDs created under the new setting, because the ID format changes for new records while existing rows keep their IDs. The step is done when the rollback test passes and the outcome is recorded in the change ticket.
What to measure when testing both generators under load
The default generator reserves blocks of IDs by writing to a shared table, so its cost shows up as contention and lock waits on that table under concurrent transactions. The StrongUuidGenerator avoids that shared row, so the question is whether the write pattern on the main tables and the ID block table changes in the way you expect. Capture these numbers from the same database and the same workload profile for both runs.
- Lock waits on the ID block table: Record the count and total wait time of lock waits touching the ID property table during peak concurrency. Expect this to be the primary signal for the default generator.
- Write volume per process start: Count inserts and updates per started instance across execution, job and variable tables. Compare totals, not just the ID table.
- Deadlocks and serialization errors: Count these per minute and note which statements are involved.
- Connection pool saturation: Track how long engine threads wait for connections, because lock waits often appear here first.
- Settings that must match: Database version, isolation level, connection pool size,
idBlockSizefor the default run, and the same seed data.
A regression is any rise in lock wait time or error rate on the non-ID tables. Confirm the exact table names and monitoring views with your database vendor before the test starts.
Engine metrics show what users and integrations experience. Throughput and start latency matter most, but retries and job errors often reveal problems that averages hide. Measure the engine at the API boundary and at the async executor, because a generator change can shift where waiting happens.
- Job throughput: Measure completed async jobs per second at steady load, using the same job definitions and the same executor configuration in both runs.
- Process start latency: Record p50, p95 and p99 latency for starting an instance through the Java or REST API. Tail latency is where contention appears.
- Retries and failed jobs: Count job retries and failed jobs, and group errors by exception type. Optimistic locking exceptions and ID-related failures should be tracked separately.
- Executor queue depth: Watch how full the job queue gets and how long jobs wait between creation and execution.
- Settings that must match: Executor thread pool and queue sizes, the process model under test, the number of engine nodes, the load generator and its ramp profile, and the Flowable version.
A regression is higher tail latency, more retries, or more failed jobs at the same throughput. Confirm which engine metrics your Flowable version exposes through the monitoring endpoints before you rely on them.
Operational effects appear after the load test ends. UUID keys change the physical layout of indexes, and the generator choice can affect how the engine behaves when a node restarts or a new node joins the cluster. These effects are slower to show up, so plan longer observation windows and include them in the test scope from the start.
- Index size and page fill: Compare index size and fragmentation on the primary key and foreign key indexes after the same number of inserts. Random UUID values insert across index pages, which can increase fragmentation.
- Insert ordering: Check whether the default run's sequential block IDs produce more localized writes than the UUID run, and measure the effect on buffer cache hit ratio.
- Node restart behavior: Restart one node during load and measure time to resume job acquisition and the number of jobs reprocessed.
- Scale-out behavior: Add a node mid-run and measure how quickly it picks up work and whether lock expiration recovery causes duplicate execution.
- Settings that must match: Table definitions, index definitions, storage type, the lock timeout configuration, and the data volume before the test begins.
A regression is index growth beyond what your storage plan allows, slower recovery after restart, or duplicate work during scale-out. Confirm the lock and recovery behavior for your version in the Flowable advanced documentation before you set expectations.
How UUID identifiers change data and reporting
Switching to the StrongUuidGenerator changes what the primary key columns hold. Instead of values that rise with each insert, Flowable writes 36-character UUID strings (or the equivalent in your database's character type) into the ID columns of the runtime, history and identity tables. Those columns are indexed, so the index now receives values scattered across its key space rather than appended at one end. That affects index size, page splits and cache behavior on busy tables, especially in the runtime execution and job tables that take the heaviest write load. Before you commit, measure the storage and index footprint of your largest tables with a realistic copy of your data, and confirm with your database vendor how wide and how randomly distributed keys affect your indexes. Confirm the exact column types Flowable creates for your version and database rather than assuming them.
Anything outside Flowable that assumes ordering or numeric IDs needs review. Dashboards that sort by ID to mean "newest first," reports that compute gaps or counts from ID ranges, archiving jobs that page through ID sequences, and integrations that store Flowable IDs in fixed-width integer fields will all break or behave unexpectedly. Ordering should move to explicit timestamp columns such as start or creation time, which the history tables already carry at the level your history setting keeps. Pay particular attention to external systems that persist process instance IDs as integers. Make an inventory of every consumer of Flowable IDs, decide which ones need UUID-aware changes, and test each one against a deployment that uses the new generator.
Changing the generator does not rewrite existing IDs. Rows created before the switch keep their numeric or block-generated values, and new rows receive UUIDs, so a single table can hold both formats during the transition. Your reporting and integrations therefore have to handle mixed ID types for as long as historical data remains, which is usually the period the history cleaning schedule keeps it. Treat the switch as a forward-only change for ID format and confirm this with the Flowable version and database you run, including how the schema and any existing ID columns are handled during the upgrade. If you need uniform IDs across old and new data, that is a separate data migration with its own planning, testing and rollback, and it should be scoped and quoted on its own.
Security and operational considerations for the change
Switching the ID generator touches more than one setting. It adds a dependency, depends on the Spring and Jackson versions in your Flowable release, and must be applied the same way on every node. The cards below cover what to review before the change, how to roll it out, and what to keep afterward.
Review the new dependency
The StrongUuidGenerator is not part of the core engine jar set, so it arrives as an extra dependency that your build must pull in. Treat it like any other library in your software bill of materials: confirm the exact artifact and version, the license, the source repository and the transitive dependencies it brings. Run your usual vulnerability scan and record the approval in your dependency register before the change is merged.
Align Spring and Jackson versions
The generator must match the Spring Framework, Spring Boot and JSON library baseline of the Flowable release you run. Flowable 8.0.0 moved to Spring Framework 7 and Spring Boot 4, dropped Spring Boot 3 compatibility and made Jackson 3 the default with a Jackson 2 compatibility layer. Check the release notes for your version and confirm that the dependency resolves to a compatible build, not a transitive version that your platform team pins differently.
Roll out the setting on every node
Flowable runs on several nodes that share one database, so a mixed configuration means some nodes write IDs with one generator and others with another. Change the generator in a single deployment unit, drain or restart nodes in a controlled sequence, and verify the configuration on each node before accepting traffic. Confirm how cluster coordination and lock behavior are described in the advanced documentation before you choose the rollout order.
Monitor the engine after the switch
Watch the metrics that the change could move: database insert latency on the runtime and history tables, failed or retried jobs, optimistic locking exceptions and the async executor's lock recovery activity. Compare these against a baseline captured before the switch. The Spring Boot actuator endpoint at the flowable path can show running process state, which helps confirm that instances continue to progress normally. Set alerts before the change window opens.
Record the change as evidence
Log the change request, the approved dependency version, the configuration diff for each node, the test results from both generators and the rollback plan in your change management system. Keep the evidence in the same place as other platform changes so that an auditor can trace who approved the switch, when it was made and what was verified. Confirm with your compliance team which records they require, since DeployOpen prepares evidence but does not issue assessments.
Plan a rollback path
Decide before the change how you will return to the default block generator if a node misbehaves. Confirm with the Flowable documentation and your own test environment whether reverting the setting requires a restart, whether IDs already written with the new generator remain valid, and whether any schema or dependency change needs to be undone. Document the steps and rehearse them once in a non-production environment.
Limits and what to confirm in your environment
The case for the StrongUuidGenerator depends on your workload and database, so treat the switch as a decision to verify rather than a default upgrade. The failure mode it addresses appears under high concurrent insert rates, and whether your system reaches that rate, and how your database handles contention on the ID block table, determines whether the change helps at all. A workload with modest process start rates may see no measurable difference, and a poorly sized database can hide the gain behind other bottlenecks. Confirm your peak job and instance creation rates from production metrics before you plan the change.
Do not copy the class name, dependency coordinates, default block size or supported versions from memory or from community posts. Take each of them from the Flowable advanced documentation and the release notes for the exact Flowable version you run, since the Flowable 8.0.0 release brought changes to the Spring and Jackson baseline that affect which dependencies you can add. Ask DeployOpen or your Flowable contact to confirm that the extra dependency is compatible with your Spring Boot, Jackson and JUnit setup, and record the version in your change request.
Results from a test environment do not transfer automatically to production. Before committing, run the same load profile against both generators on a database that matches production in engine version, instance type, connection pool size, indexes and history level, and compare throughput, lock waits and the rate of optimistic locking exceptions. Ask your database team to confirm how the ID generation writes behave under your replication and failover setup, and plan a rollback path that does not require rewriting existing IDs. Repeat the test after any change to the async executor or history configuration, because those settings change the same write pattern.
Questions teams ask before changing the Flowable ID generator
Should we switch to the StrongUuidGenerator or tune the ID block size first?
Tune the block size first when the database sequence is the only bottleneck and your node count is small, and switch when concurrent nodes keep contending for the same ID block even after tuning. Block tuning changes the idBlockSize setting and is a configuration change you can test quickly. Switching changes how IDs are produced, adds a dependency, and needs a load test that compares both generators on your own schema. Decide from measured contention on the database, not from the number of nodes alone, because a single node with a heavy write pattern can also show the problem.
Can our internal team make the switch without outside help?
Yes, if your engineers already own the Flowable deployment, can change the engine configuration and dependencies, and can run a realistic load test against a staging environment that matches production. The work is small in code but depends on evidence: you need database metrics during the test, a repeatable load profile, and a way to compare results before and after. Teams that lack load tooling, staging access, or experience reading database contention data often take longer and may miss the failure mode until production. An outside partner can cover the test design and analysis, or you can keep that in-house and ask for a review.
What drives the cost and effort of this change?
The main drivers are the number of engine nodes and databases involved, the test environment you can use, the shape of your load profile, and how well your Flowable, Spring and Java versions already line up with the dependency you need. Each of these changes how many test cycles you run and how much analysis the results require. One-time costs include the assessment, configuration, dependency changes and load test runs. Recurring costs are small but real: you must repeat the test after Flowable upgrades or when the workload changes. Ask any quote to list each of these items separately.
How long will the switch take?
No fixed duration applies to every environment, because the timeline depends on how many load test cycles the results require. A clean run may finish quickly, while a result that shows an unexpected bottleneck adds investigation and another round of testing. Ask for a timeline that is tied to named test cycles, the environment access dates and the review points, rather than a single total. Confirm with your own change calendar how long a production change window needs to be.
What do we need to provide before the work starts?
Plan to provide staging access that matches production topology, read access to database metrics for the test and the live system, the load generation tooling you already use or agree to use, and a set of realistic process workloads. You also need a change window for the production rollout and a named owner who can approve configuration changes. Missing any of these usually pushes the work into delays, because the test results depend on them. Confirm each item in the written scope before the engagement begins.
Does switching the ID generator change how our existing process data looks?
Engineers should check this before any change. IDs generated by a different strategy have a different format, so code, reports, queries or integrations that assume a numeric or sequential pattern can break. Review any external system that stores or matches Flowable IDs, and test those paths in staging. Also confirm how existing IDs in running and historical data remain valid after the change, since the new generator should not rewrite them. Verify this against the Flowable configuration documentation for your version.
What should our engineers check when testing both generators under load?
Measure both generators with the same workload, data volume and node count, and record database contention, lock wait time, throughput and error counts such as failed inserts or optimistic locking exceptions. Repeat each run enough times to see variation, and test the failure point, not only the average. Confirm the extra dependency loads correctly with your Spring and Java versions, and check that the configuration you chose survives a restart. Keep the results so you can repeat the comparison after upgrades.
Are there any security concerns with a UUID-based ID generator?
The main security question is whether you rely on IDs being unguessable or unordered for access control. Flowable does not enforce authorization on IDs, so your application must still check who may view or act on each process instance. Confirm your authorization model covers any API that accepts an ID, and review logs that record IDs in case they reveal information. Check the Flowable security documentation for your version before deciding that UUID format alone limits exposure.
How DeployOpen scopes and delivers Flowable ID generator work
DeployOpen approaches Flowable ID generator work as a fixed-scope engagement inside your own infrastructure. We start by measuring whether the default database ID block generator is the actual bottleneck, then agree in writing on how the StrongUuidGenerator change, its dependency and its load tests will be delivered.
How we scope
- Confirm whether your Flowable version and database show ID block contention before any generator change is proposed.
- Write down the target engine version, the database type, and the nodes that will generate IDs under load.
- Agree in writing which load profiles, idBlockSize settings and both generator configurations are in scope.
How we build
- Add the StrongUuidGenerator dependency and configuration in a branch that your build pipeline can promote.
- Run the same concurrent insert workload against the default generator and the UUID generator with recorded results.
- Tune idBlockSize only against measured contention, and document every value we tested and why we chose it.
How we hand over
- Deliver the configuration, dependency changes and load test scripts to your repository, with setup notes for your team.
- Document the rollback path to the default generator, including what must be verified in the database before switching back.
- Walk your engineers through the test results so they can rerun the tests after future Flowable upgrades.
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer if your team wants us to keep the setup current.
- Retainer work can include rechecking the generator setting when you move to a new Flowable release line.
- Ask any partner for the written scope, deliverables and handover list before agreeing on the work and its timing.

