CompactRef
Generate compact, human-facing references from ULIDs, UUIDs and other stable internal identifiers.
CompactRef is useful when an application keeps a full internal identifier but needs a shorter reference for users, support teams, documents or searches.
CompactRef generates compact references, not globally unique identifiers.
A short reference has fewer possible values than the identifier it is derived from, so two identifiers can produce the same reference. Keep the ULID or UUID as the primary key, put a unique constraint on the reference column, and use
attemptto derive another one when that constraint rejects a write. Choosing a suffix length sizes the reference so this stays rare.
Installation
pip install compactref
Generate a reference from a ULID
from compactref import generate_reference
reference = generate_reference(
"01J2H8NQPG6B5X8KGN97SX3R5C",
)
print(reference)
Possible output:
20260710482731
Add a prefix and separators
from compactref import generate_reference
reference = generate_reference(
"01J2H8NQPG6B5X8KGN97SX3R5C",
prefix="INC",
separator="-",
)
print(reference)
Possible output:
INC-20260710-482731
Use a UUID
from uuid import uuid4
from compactref import generate_reference
internal_id = uuid4()
reference = generate_reference(internal_id)
Configure the suffix length
reference = generate_reference(
"01J2H8NQPG6B5X8KGN97SX3R5C",
suffix_length=8,
)
Possible output:
2026071048273164
Change the date format
The date_format argument accepts any datetime.strftime pattern. A
finer-grained format also produces smaller collision buckets (see
Choosing a suffix length).
reference = generate_reference(
"01J2H8NQPG6B5X8KGN97SX3R5C",
date_format="%Y%m%d-%H",
separator="-",
prefix="INC",
)
Possible output:
INC-20260710-14-482731
Use an integer or bytes identifier
from compactref import generate_reference
from_integer = generate_reference(123456789)
from_bytes = generate_reference(b"internal-record-123")
Deterministic generation
The same identifier, date and configuration produce the same reference:
from datetime import datetime
from compactref import generate_reference
generated_at = datetime(2026, 7, 10)
first = generate_reference(
"01J2H8NQPG6B5X8KGN97SX3R5C",
generated_at=generated_at,
)
second = generate_reference(
"01J2H8NQPG6B5X8KGN97SX3R5C",
generated_at=generated_at,
)
assert first == second
Recovering from a collision
Because a reference is derived from its source, the same source always produces the same reference. Retrying a rejected reference therefore returns the identical string, however many times you ask.
attempt is what makes a unique constraint recoverable. Raising it
derives a different reference from the same source, so when attempt 0
is already taken you can offer attempt 1:
from compactref import generate_reference
def assign_reference(session, product):
for attempt in range(10):
reference = generate_reference(
product.id,
prefix="RDR",
separator="-",
attempt=attempt,
)
if not session.query(exists_reference(reference)).scalar():
return reference
raise RuntimeError("ten attempts collided; the suffix is too short")
Each attempt is deterministic in its own right, so a reference remains recomputable later from the source and the attempt that won — store the attempt alongside the reference if you need to rederive it.
first = generate_reference("01J2H8NQPG6B5X8KGN97SX3R5C")
second = generate_reference("01J2H8NQPG6B5X8KGN97SX3R5C", attempt=1)
assert first != second
assert second == generate_reference(
"01J2H8NQPG6B5X8KGN97SX3R5C",
attempt=1,
)
attempt defaults to 0, which reproduces the references CompactRef
produced before the argument existed. References already stored by
callers on 0.1.0 remain valid.
Reaching for attempt on most writes is a sign the suffix is too short,
not that the retry loop is working. Size it with expected_collisions()
below.
Supported source types
CompactRef accepts:
- ULIDs represented as strings
- UUID objects
- strings
- bytes
- non-negative integers
Choosing a suffix length
A reference is unique only within a single bucket — references that share the same prefix and date part. Because the date resets each day, what matters is how many references you expect per bucket (for the default format, per day), not the all-time total.
Two helpers size the suffix using the birthday model.
Estimate the collision risk
collision_probability(reference_count, suffix_length) returns the
probability that at least two references in one bucket share the same
suffix:
from compactref import collision_probability
collision_probability(50, suffix_length=4) # 0.1153 -> ~11.5%
collision_probability(50, suffix_length=6) # 0.0012 -> ~0.1%
collision_probability(120, suffix_length=4) # 0.5103 -> coin flip
Count the collisions, not just the risk
collision_probability() saturates. Past a certain volume every format
reports "almost certainly", which stops separating a format that
collides twice a month from one that collides fifty times.
expected_collisions(reference_count, suffix_length) returns how many
pairs are expected to share a suffix in one bucket. With a unique
constraint in place, a collision is a rejected insert, so this is really
an error rate — the number of writes per bucket that will need an
attempt retry:
from compactref import collision_probability, expected_collisions
collision_probability(2_000, suffix_length=3) # 1.0 -> "certain"
collision_probability(20_000, suffix_length=3) # 1.0 -> "certain", equally
expected_collisions(2_000, suffix_length=3) # 1999 pairs
expected_collisions(20_000, suffix_length=3) # 199990 pairs
Both formats are certain to collide. Only the second number tells you how badly.
Find a safe volume
max_references(suffix_length, max_probability=0.01) returns the
largest number of references that keeps the risk at or below the
threshold (1% by default):
from compactref import max_references
max_references(4) # 14 -> under 1% risk with 4 digits
max_references(6) # 142 -> under 1% risk with 6 digits
max_references(6, 0.05) # 320 -> if you accept up to 5% risk
Pick a length for your volume
from compactref import collision_probability
expected_per_day = 200
for length in range(4, 9):
risk = collision_probability(expected_per_day, suffix_length=length)
print(f"{length} digits -> {risk:.3%}")
# 4 digits -> 86.330%
# 5 digits -> 18.045%
# 6 digits -> 1.970%
# 7 digits -> 0.199%
# 8 digits -> 0.020%
For roughly 200 references per day, a 7-digit suffix keeps the risk well under 1%.
Uniqueness warning
CompactRef does not replace the original internal identifier.
Shortening an identifier reduces the number of possible values. Different internal identifiers can produce the same compact reference. No suffix length makes this impossible; a longer one only makes it rarer.
Applications requiring unique references should:
- Keep the original ULID or UUID as the internal identifier. The reference is for humans; the identifier is for the database.
- Add a unique constraint to the reference column, so a collision surfaces as a rejected write rather than two products quietly sharing a reference.
- Handle that rejection by retrying with a higher
attempt, as in Recovering from a collision. - Size
suffix_lengthfor the expected volume per bucket, usingexpected_collisions(), so step 3 stays a rare path rather than the normal one.
Requirements
Python 3.10 or newer. No runtime dependencies.
Changelog
See CHANGELOG.md.
Version 0.2.0 added the attempt argument and expected_collisions().
References produced by 0.1.0 are unchanged: attempt defaults to 0, which
reproduces them byte for byte, so anything already stored stays valid.
Contributing
Issues and pull requests are welcome at github.com/neosergio/compactref.
Maintainers: see RELEASING.md for how a version reaches PyPI.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file compactref-0.2.0.tar.gz.
File metadata
- Download URL: compactref-0.2.0.tar.gz
- Upload date:
- Size: 13.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a93c6dff348f30437be8fef53f5d5c7d2746fa2c7cca7a985bdc517b21bb3577
|
|
| MD5 |
1d121ce2e0f8aa8082ea4d7ad8dfb400
|
|
| BLAKE2b-256 |
60f4cd4a21e8a36e839051cc007d5b364d3c81234c854b1af2a97f28f399b065
|
Provenance
The following attestation bundles were made for compactref-0.2.0.tar.gz:
Publisher:
publish.yml on neosergio/compactref
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
compactref-0.2.0.tar.gz -
Subject digest:
a93c6dff348f30437be8fef53f5d5c7d2746fa2c7cca7a985bdc517b21bb3577 - Sigstore transparency entry: 2164336263
- Sigstore integration time:
-
Permalink:
neosergio/compactref@8992ac928c87cda37a774fe52ec8c5aa076041d8 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/neosergio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8992ac928c87cda37a774fe52ec8c5aa076041d8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file compactref-0.2.0-py3-none-any.whl.
File metadata
- Download URL: compactref-0.2.0-py3-none-any.whl
- Upload date:
- Size: 8.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
713a2fb2787fbf3b50e850eb884614dbef06de64f062cf3c2c21d030073135fd
|
|
| MD5 |
15be123f74d2bc4bf79aae6f6cefaa66
|
|
| BLAKE2b-256 |
6903df0c39a2069a8df1f12291cb69853e09e0990bf79193a278114e39446299
|
Provenance
The following attestation bundles were made for compactref-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on neosergio/compactref
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
compactref-0.2.0-py3-none-any.whl -
Subject digest:
713a2fb2787fbf3b50e850eb884614dbef06de64f062cf3c2c21d030073135fd - Sigstore transparency entry: 2164336271
- Sigstore integration time:
-
Permalink:
neosergio/compactref@8992ac928c87cda37a774fe52ec8c5aa076041d8 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/neosergio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8992ac928c87cda37a774fe52ec8c5aa076041d8 -
Trigger Event:
release
-
Statement type: