Refactor UUIDs to UUID7
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Description
dotCMS currently uses UUID4 (UUID.randomUUID()) for all content inodes and system identifiers. Migrating to UUID7 (time-ordered, RFC 9562) provides measurable PostgreSQL performance improvements due to sequential B-tree insertion patterns.
Benchmark references:
- PostgreSQL UUID Performance: Random v4 and Time-Based v7
- Postgres: Benchmark UUIDv4 vs UUIDv7 Primary Keys
- UUID Benchmark War
| Metric | UUID4 | UUID7 | Notes |
|---|---|---|---|
| Insert throughput | 2,670 tps | 3,420 tps | ~28% faster; B-tree page splits eliminated |
| Insert avg latency | 35,606 ns | 18,195 ns | ~49% faster on BTREE index |
| Index size | baseline | ~22% smaller | Sequential packing, fewer splits |
| Point lookups | 65,840 ns avg | 67,727 ns avg | Roughly equivalent on BTREE |
| Range scans | baseline | faster | Temporal locality reduces I/O |
| Cache pressure | high | lower | Random UUID4 scatters hot pages across buffer cache |
Point lookups are roughly equivalent between UUID4 and UUID7 on BTREE indexes. The primary benefits are write throughput, index compaction, and cache efficiency — which compound at scale.
UUID7 is natively supported in Java 21, which dotCMS already runs on.
Technical Findings (Codebase Audit)
UUID generation is centralized — two primary files handle generation:
dotCMS/src/main/java/com/dotmarketing/util/UUIDGenerator.java— HibernateIdentifierGeneratorimpldotCMS/src/main/java/com/dotmarketing/util/UUIDUtil.java— utility methods
Scale of change:
- 27 files call
UUID.randomUUID()directly (should route throughUUIDGenerator) - 113 files transitively use
UUIDGeneratororUUIDUtil - 14 Hibernate entities use
UUIDGeneratorviaDotCMSId.hbm.xml - 26 startup/migration task files generate UUIDs
- All UUID columns are
varchar(36)— no schema changes needed (UUID7 is same length)
Format validation is UUID7-safe:
UUIDUtil.isUUID() validates [a-fA-F0-9]{32} — UUID7 passes unchanged.
Critical: ShortyAPI Impact
The ShortyIdAPI generates short IDs by taking the first N characters of a UUID (default: 10 chars, configurable via MINIMUM_SHORTY_ID_LENGTH):
// StringUtils.java
public static String shortify(final String shortStr, final int minLength) {
final String trimmedShortStr = shortStr.trim().replaceAll("-", "");
return trimmedShortStr.substring(0, min); // takes FIRST N chars
}
UUID7 encodes a 48-bit Unix millisecond timestamp in its high-order bits. This means all UUIDs generated within the same millisecond share identical first 12 hex characters. With a 10-char shorty minimum, bulk operations (imports, migrations, batch content creation) will generate colliding shorty IDs.
This must be fixed as part of this migration. Recommended fix: hash-based shorty using the already-imported com.google.common.hash.Hashing:
// Replace prefix-slicing with hash prefix — format-agnostic, collision-resistant
return Hashing.sha256()
.hashString(trimmedShortStr, StandardCharsets.UTF_8)
.toString()
.substring(0, min);
This decouples shorty uniqueness from UUID format and works for UUID4, UUID7, ULID, or any future identifier type.
Acceptance Criteria
-
UUIDGenerator.generateUuid()andUUIDUtil.uuid()produce UUID7 - All 27 direct
UUID.randomUUID()call sites consolidated throughUUIDGenerator -
StringUtils.shortify()updated to use hash-based prefix (collision-safe with UUID7) - Existing UUID4 records coexist without schema changes (mixed state is permanent and acceptable)
- Integration tests pass with UUID7-generated inodes
- ShortyAPI resolves both UUID4 (existing) and UUID7 (new) records correctly
Implementation Phases
Medium complexity — 4 phases:
- UUID7 factory, update central generators, feature flag
- Fix ShortyAPI (
shortifyhash change), test mixed UUID4/UUID7 lookups - Consolidate 27 direct
randomUUID()calls, update 26 startup tasks - Integration testing, regression, cleanup
Priority
Low
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with dotCMS/src/main/java/com/dotmarketing/util/UUIDGenerator.java and UUIDUtil.java, then inspect StringUtils.shortify() and the listed direct UUID.randomUUID() call sites. Run the relevant integration and ShortyAPI tests before changing behavior. Done means UUID7 generation, consolidated call sites, hash-based short IDs, and correct coexistence and lookup of UUID4 and UUID7 records.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, postgresql
- Domain
- backend, databases
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100