A ULIDGenerator is responsible for producing ULIDs by sampling a clock, sourcing entropy, and applying a monotonicity policy. While the default ULID() constructor uses a shared default_generator, you can create custom generators to control behavior.
Monotonicity Policies
When multiple ULIDs are generated within the same millisecond, the policy determines how the randomness component is handled:
StrictMonotonicPolicy (Default): Increments the randomness by 1 for same-millisecond collisions. If the randomness is exhausted, it raises a ValueError.LaxMonotonicPolicy: Increments the randomness by 1 for same-millisecond collisions. If randomness is exhausted, it regenerates fresh randomness instead of raising an error.PureRandomPolicy: Ignores previous state and always draws fresh randomness. This maximizes entropy but sacrifices the guaranteed monotonic sort order within the same millisecond.
Customizing the Global Generator
You can override the global ulid.default_generator so that all calls to ULID() and ULID.from_* use your custom configuration.
import ulid
from ulid import ULID, ULIDGenerator, LaxMonotonicPolicy
# 1. Using a custom generator instance
generator = ULIDGenerator(policy=LaxMonotonicPolicy())
new_ulid = generator.generate()
# 2. Overriding the global default generator
ulid.default_generator = ULIDGenerator(policy=LaxMonotonicPolicy())
# Now all ULID() calls use the Lax policy
new_ulid_global = ULID()