dotCMS / dotCMS/core

Refactor UUIDs to UUID7

Open
#35,280 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

OKR : Application Performance stale
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:

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 — Hibernate IdentifierGenerator impl
  • dotCMS/src/main/java/com/dotmarketing/util/UUIDUtil.java — utility methods

Scale of change:

  • 27 files call UUID.randomUUID() directly (should route through UUIDGenerator)
  • 113 files transitively use UUIDGenerator or UUIDUtil
  • 14 Hibernate entities use UUIDGenerator via DotCMSId.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() and UUIDUtil.uuid() produce UUID7
  • All 27 direct UUID.randomUUID() call sites consolidated through UUIDGenerator
  • 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:

  1. UUID7 factory, update central generators, feature flag
  2. Fix ShortyAPI (shortify hash change), test mixed UUID4/UUID7 lookups
  3. Consolidate 27 direct randomUUID() calls, update 26 startup tasks
  4. Integration testing, regression, cleanup
Priority

Low

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.