DEV Community

Cover image for Designing a topology-aware UUID v8-style Java library for distributed systems
Louis Franck M
Louis Franck M

Posted on

Designing a topology-aware UUID v8-style Java library for distributed systems

Most ID libraries solve one problem well:

uniqueness

But in distributed systems, that is often not enough.

Sometimes you also want an identifier to help with:

  1. - ordering
  2. - tracing
  3. - debugging
  4. - understanding where it came from

That is why I built EUID, a Java library for generating sortable, decodable, topology-aware UUID v8-style identifiers.

With v0.2.0, I made the biggest change to the project so far: I split generation into two strategies instead of forcing one implementation to handle every workload.

Why EUID exists

Traditional UUIDs are great when you want opaque, globally unique values.

But they do not help much when your system also cares about:

  • time ordering
  • infrastructure visibility
  • decoding metadata from an ID
  • understanding distributed generation behavior

EUID is designed for those cases.

It uses a structured 128-bit layout with:

  • timestamp
  • region
  • shard
  • node
  • sequence

So the ID is not just unique — it can also be decoded and understood.

What changed in v0.2.0

The biggest change in v0.2.0 was the generator model.

Instead of one generation strategy, EUID now provides two:

FastEuidGenerator

Optimized for:

  • single-threaded use
  • thread-confined use
  • minimal overhead

ConcurrentEuidGenerator

Optimized for:

  • shared concurrent use
  • multi-threaded access to the same generator
  • better scalability under contention

This made the library much more honest.

Different workloads do not always need the same generator behavior, so the API now reflects that.

API example

Fast generator

EuidGenerator generator = EuidGenerators.fast(1, 1, 1);
Enter fullscreen mode Exit fullscreen mode

Concurrent generator

EuidGenerator generator = EuidGenerators.concurrent(1, 1, 1);
Enter fullscreen mode Exit fullscreen mode

Concurrent generator with custom block size

EuidGenerator generator = EuidGenerators.concurrent(1, 1, 1, 2048);
Enter fullscreen mode Exit fullscreen mode

Decode support

One of the key goals of EUID is that IDs should be useful to inspect.

UUID id = EuidGenerators.fast(2, 3, 4).generate();

DecodedEuid decoded = EuidDecoder.decode(id);

System.out.println(decoded.getInstant());
System.out.println(decoded.getRegion());
System.out.println(decoded.getShard());
System.out.println(decoded.getNode());
System.out.println(decoded.getSequence());
Enter fullscreen mode Exit fullscreen mode

That is useful for:

  • debugging distributed systems
  • tracing event origins
  • validating routing or sharding behavior

Base58 support

EUID also supports Base58 encoding for more compact external representation.

UUID id = EuidGenerators.fast(1, 1, 1).generate();

String encoded = EuidBase58Codec.encode(id);
UUID decoded = EuidBase58Codec.decode(encoded);
Enter fullscreen mode Exit fullscreen mode

This is useful when you want:

  • shorter IDs
  • better readability
  • easier copy/paste in logs or URLs

Benchmarks

For v0.2.0, I also created a separate JMH benchmark project and benchmarked:

  • raw generation
  • multi-thread throughput
  • generation + toString()
  • Base58 encoding/decoding

Highlights for euid-core:0.2.0

Raw generation

  • * ConcurrentEuidGenerator: ~262.8M ops/s
  • * FastEuidGenerator: ~254.8M ops/s
  • * tested UUID v7 library: ~68.4M ops/s

Multi-thread

  • * FastEuidGenerator (per thread): ~850.7M ops/s
  • * ConcurrentEuidGenerator (per thread): ~848.2M ops/s
  • * ConcurrentEuidGenerator (shared): ~826.3M ops/s
  • * tested UUID v7 library: ~39.6M ops/s

Generate + toString()

  • * FastEuidGenerator: ~68.5M ops/s
  • * ConcurrentEuidGenerator: ~59.8M ops/s
  • * tested UUID v7 library: ~40.2M ops/s

Base58

  • * encode: ~1.4M to ~1.5M ops/s
  • * decode: ~2.07M ops/s

The benchmark results helped clarify an important point:

  • * raw generation is very fast
  • * string conversion changes the overall picture
  • * Base58 is useful, but comes with a real cost

What I learned

A few things became clear while working on this release:

  1. One generator strategy was not enough

Different workloads genuinely benefit from different generation models.

  1. Benchmarking needs discipline

Focused JMH runs gave much more meaningful results than broad mixed runs.

  1. IDs can be operational tools

For some systems, an ID that carries structure is more useful than a purely opaque value.

When EUID makes sense

EUID is a good fit if you want:

  • sortable IDs
  • topology-aware IDs
  • decode support
  • strong throughput
  • more operational visibility from identifiers

It is probably not the right choice if:

  • you only need random uniqueness
  • you want fully opaque IDs
  • UUID v4 or UUID v7 already fully solves your use case

EUID is not trying to replace every UUID scenario.

It is aimed at systems that benefit from sortable, decodable, infrastructure-aware identifiers.

Current status

The project is currently at v0.2.0.

At this stage, I am more focused on:

  • documentation
  • benchmark communication
  • API clarity

than rushing to 1.0.0.

I would rather have a well-understood 0.2.x than a premature “stable” release.

Feedback welcome

I’d be very interested in feedback on:

  • the API design
  • the benchmark methodology
  • tradeoffs vs UUID v7
  • tradeoffs vs Snowflake-style IDs
  • real distributed-system use cases

GitHub logo louis-franck-moussima / euid-java

Core library for EUID — a fast, distributed, sortable unique ID generator for Java.

EUID — Topology-Aware UUID v8 for Java

Maven Central License Java

EUID is a Java library for generating sortable, decodable, infrastructure-aware UUID v8 identifiers.

It is designed for distributed systems that need more than raw uniqueness:

  • time-ordered IDs for better database locality
  • embedded topology metadata (region, shard, node)
  • deterministic per-node sequencing
  • RFC 4122 / UUID v8-compatible layout
  • human-friendlier Base58 encoding
  • full decode support for observability and debugging

If you need identifiers that are not just unique, but also operationally meaningful, EUID gives you a structured alternative to purely random UUIDs.


Why EUID?

Traditional identifiers solve uniqueness, but they do not always help with:

  • ordered inserts in databases
  • infrastructure traceability
  • decoding where an ID came from
  • correlating events across distributed nodes

EUID is built for those cases.

In one sentence

EUID = sortable UUID v8 + topology metadata + deterministic sequencing


When to use EUID

EUID is a good…

Top comments (0)