Top Related Projects
Universally Unique Lexicographically Sortable Identifier (ULID) in Go
xid is a globally unique id generator thought for the web
UUID package for Go
Go package for UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
Collision-resistant ids optimized for horizontal scaling and performance.
Quick Overview
KSUID (K-Sortable Unique IDentifier) is a Go library for generating globally unique identifiers with improved sorting and lexicographic ordering. It combines the benefits of time-based sorting with the advantages of random UUIDs, making it suitable for distributed systems and databases.
Pros
- Sortable: KSUIDs can be sorted chronologically, enabling efficient time-based queries
- Collision-resistant: Extremely low probability of generating duplicate IDs
- URL-safe: Can be used in URLs without encoding
- Compact: More space-efficient than UUIDs
Cons
- Limited adoption: Not as widely used or recognized as UUIDs
- Language-specific: Primarily designed for Go, though ports to other languages exist
- Timestamp precision: Limited to second-level precision for sorting
Code Examples
- Generating a new KSUID:
import "github.com/segmentio/ksuid"
id := ksuid.New()
fmt.Println(id.String()) // Prints a new KSUID
- Parsing a KSUID from a string:
import "github.com/segmentio/ksuid"
id, err := ksuid.Parse("0ujtsYcgvSTl8PAuAdqWYSMnLOv")
if err != nil {
log.Fatal(err)
}
fmt.Println(id.Time()) // Prints the timestamp of the KSUID
- Comparing KSUIDs:
import "github.com/segmentio/ksuid"
id1 := ksuid.New()
id2 := ksuid.New()
if id1.Compare(id2) < 0 {
fmt.Println("id1 is older than id2")
} else {
fmt.Println("id1 is newer than or equal to id2")
}
Getting Started
To use KSUID in your Go project, follow these steps:
-
Install the library:
go get github.com/segmentio/ksuid
-
Import the package in your Go code:
import "github.com/segmentio/ksuid"
-
Generate and use KSUIDs:
id := ksuid.New() fmt.Println("New KSUID:", id.String())
That's it! You can now start using KSUIDs in your Go applications.
Competitor Comparisons
Universally Unique Lexicographically Sortable Identifier (ULID) in Go
Pros of ULID
- Lexicographically sortable, allowing for efficient database indexing
- Includes millisecond precision timestamp, providing more granular time information
- Supports case-insensitive sorting, making it more flexible in various environments
Cons of ULID
- Slightly longer string representation (26 characters) compared to KSUID (27 characters)
- Less random entropy (80 bits) compared to KSUID (128 bits)
- May have potential for collisions in high-volume, distributed systems due to lower entropy
Code Comparison
ULID:
id := ulid.MustNew(ulid.Timestamp(time.Now()), entropy)
fmt.Printf("ULID: %s\n", id.String())
KSUID:
id := ksuid.New()
fmt.Printf("KSUID: %s\n", id.String())
Both ULID and KSUID provide unique identifier solutions with timestamps, but they differ in their approach to sortability, entropy, and string representation. ULID offers better sortability and more precise timestamps, while KSUID provides higher entropy and a slightly more compact representation. The choice between the two depends on specific use cases and requirements, such as the need for lexicographic sorting or the importance of collision resistance in high-volume systems.
xid is a globally unique id generator thought for the web
Pros of xid
- Smaller size: 12 bytes compared to KSUID's 20 bytes
- Faster generation due to simpler structure
- Better suited for high-performance scenarios
Cons of xid
- Less entropy than KSUID (64 bits vs 128 bits)
- No built-in sorting capability like KSUID
- Less human-readable when encoded
Code Comparison
xid:
id := xid.New()
fmt.Printf("xid: %s\n", id.String())
KSUID:
id := ksuid.New()
fmt.Printf("ksuid: %s\n", id.String())
Both xid and KSUID are Go libraries for generating unique identifiers, but they have different approaches and trade-offs. xid focuses on performance and compact size, making it suitable for high-throughput systems. KSUID, on the other hand, prioritizes higher entropy and sortability, which can be beneficial for distributed systems and databases.
xid uses a combination of timestamp, machine ID, and process ID, while KSUID incorporates a timestamp and random data. The choice between the two depends on specific project requirements, such as storage constraints, sorting needs, and performance demands.
UUID package for Go
Pros of go.uuid
- Implements standard UUID versions (v1, v3, v4, v5)
- Provides compatibility with existing UUID-based systems
- Offers a more compact representation (16 bytes)
Cons of go.uuid
- Less sortable than KSUID
- Doesn't include timestamp information
- May have higher collision probability in distributed systems
Code Comparison
go.uuid:
import "github.com/satori/go.uuid"
id := uuid.NewV4()
fmt.Printf("UUID: %s\n", id)
ksuid:
import "github.com/segmentio/ksuid"
id := ksuid.New()
fmt.Printf("KSUID: %s\n", id)
Key Differences
- Format: go.uuid generates standard UUIDs, while ksuid creates sortable, time-ordered unique identifiers.
- Timestamp: ksuid includes a timestamp component, making it useful for time-based sorting and querying.
- Size: UUIDs are 16 bytes, while KSUIDs are 20 bytes.
- Sorting: KSUIDs are inherently sortable, UUIDs are not.
- Use cases: go.uuid is better for systems requiring standard UUID compatibility, while ksuid is ideal for distributed systems needing sortable, collision-resistant IDs.
Both libraries offer efficient ways to generate unique identifiers, but they cater to different use cases and requirements. The choice between them depends on specific project needs, such as sortability, timestamp inclusion, or compatibility with existing systems.
Go package for UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
Pros of uuid
- Widely adopted and recognized standard for unique identifiers
- Supports multiple UUID versions (v1, v3, v4, v5)
- Provides a stable and mature implementation
Cons of uuid
- Fixed 128-bit size, which can be less efficient for storage and indexing
- Not sortable by generation time, limiting its use in time-based ordering scenarios
- Lacks built-in support for custom metadata or namespacing
Code Comparison
uuid:
import "github.com/google/uuid"
id := uuid.New()
fmt.Printf("UUID: %s\n", id.String())
ksuid:
import "github.com/segmentio/ksuid"
id := ksuid.New()
fmt.Printf("KSUID: %s\n", id.String())
Key Differences
- ksuid generates sortable, time-ordered unique identifiers
- ksuid includes a timestamp component, allowing for chronological sorting
- uuid offers more flexibility with different versions and namespacing options
- ksuid provides a more compact representation (27 characters) compared to uuid (36 characters)
- ksuid is designed for better performance in distributed systems and databases
Both libraries offer efficient ways to generate unique identifiers, but they cater to different use cases. uuid is more suitable for general-purpose unique ID generation, while ksuid excels in scenarios requiring time-ordered, sortable identifiers with better database performance.
Collision-resistant ids optimized for horizontal scaling and performance.
Pros of cuid
- Supports multiple programming languages (JavaScript, Python, PHP, etc.)
- Designed to be collision-resistant in distributed systems
- Includes a timestamp component for chronological sorting
Cons of cuid
- Longer ID length (25 characters) compared to KSUID (27 characters)
- Less entropy than KSUID (only uses lowercase letters and numbers)
- Not as performant as KSUID for high-volume ID generation
Code Comparison
cuid:
import { createId } from '@paralleldrive/cuid2';
const id = createId();
console.log(id); // Example output: k0rxw1r9zxkagjvlq8qsk7d8
KSUID:
import "github.com/segmentio/ksuid"
id := ksuid.New()
fmt.Println(id.String()) // Example output: 0ujtsYcgvSTl8PAuAdqWYSMnLOv
Summary
Both cuid and KSUID offer unique ID generation solutions, but they cater to different needs. cuid focuses on collision resistance in distributed systems and supports multiple languages, while KSUID provides higher entropy and better performance for high-volume ID generation. The choice between the two depends on specific project requirements, such as the need for cross-language support, ID length constraints, or performance considerations in high-throughput scenarios.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
ksuid
ksuid is an efficient, comprehensive, battle-tested Go library for generating and parsing a specific kind of globally unique identifier called a KSUID. This library serves as its reference implementation.
Install
go get -u github.com/segmentio/ksuid
What is a KSUID?
KSUID is for K-Sortable Unique IDentifier. It is a kind of globally unique identifier similar to a RFC 4122 UUID, built from the ground-up to be "naturally" sorted by generation timestamp without any special type-aware logic.
In short, running a set of KSUIDs through the UNIX sort
command will result
in a list ordered by generation time.
Why use KSUIDs?
There are numerous methods for generating unique identifiers, so why KSUID?
- Naturally ordered by generation time
- Collision-free, coordination-free, dependency-free
- Highly portable representations
Even if only one of these properties are important to you, KSUID is a great choice! :) Many projects chose to use KSUIDs just because the text representation is copy-and-paste friendly.
For a follow up read on the topic: A brief history of UUID
1. Naturally Ordered By Generation Time
Unlike the more ubiquitous UUIDv4, a KSUID contains a timestamp component that allows them to be loosely sorted by generation time. This is not a strong guarantee (an invariant) as it depends on wall clocks, but is still incredibly useful in practice. Both the binary and text representations will sort by creation time without any special sorting logic.
2. Collision-free, Coordination-free, Dependency-free
While RFC 4122 UUIDv1s do include a time component, there aren't enough bytes of randomness to provide strong protection against collisions (duplicates). With such a low amount of entropy, it is feasible for a malicious party to guess generated IDs, creating a problem for systems whose security is, implicitly or explicitly, sensitive to an adversary guessing identifiers.
To fit into a 64-bit number space, Snowflake IDs and its derivatives require coordination to avoid collisions, which significantly increases the deployment complexity and operational burden.
A KSUID includes 128 bits of pseudorandom data ("entropy"). This number space is 64 times larger than the 122 bits used by the well-accepted RFC 4122 UUIDv4 standard. The additional timestamp component can be considered "bonus entropy" which further decreases the probability of collisions, to the point of physical infeasibility in any practical implementation.
3. Highly Portable Representations
The text and binary representations are lexicographically sortable, which allows them to be dropped into systems which do not natively support KSUIDs and retain their time-ordered property.
The text representation is an alphanumeric base62 encoding, so it "fits" anywhere alphanumeric strings are accepted. No delimiters are used, so stringified KSUIDs won't be inadvertently truncated or tokenized when interpreted by software that is designed for human-readable text, a common problem for the text representation of RFC 4122 UUIDs.
How do KSUIDs work?
Binary KSUIDs are 20-bytes: a 32-bit unsigned integer UTC timestamp and a 128-bit randomly generated payload. The timestamp uses big-endian encoding, to support lexicographic sorting. The timestamp epoch is adjusted to May 13th, 2014, providing over 100 years of life. The payload is generated by a cryptographically-strong pseudorandom number generator.
The text representation is always 27 characters, encoded in alphanumeric base62 that will lexicographically sort by timestamp.
High Performance
This library is designed to be used in code paths that are performance
critical. Its code has been tuned to eliminate all non-essential
overhead. The KSUID
type is derived from a fixed-size array, which
eliminates the additional reference chasing and allocation involved in
a variable-width type.
The API provides an interface for use in code paths which are sensitive
to allocation. For example, the Append
method can be used to parse the
text representation and replace the contents of a KSUID
value
without additional heap allocation.
All public package level "pure" functions are concurrency-safe, protected
by a global mutex. For hot loops that generate a large amount of KSUIDs
from a single Goroutine, the Sequence
type is provided to elide the
potential contention.
By default, out of an abundance of caution, the cryptographically-secure
PRNG is used to generate the random bits of a KSUID. This can be relaxed
in extremely performance-critical code using the included FastRander
type. FastRander
uses the standard PRNG with a seed generated by the
cryptographically-secure PRNG.
NOTE: While there is no evidence that FastRander
will increase the
probability of a collision, it shouldn't be used in scenarios where
uniqueness is important to security, as there is an increased chance
the generated IDs can be predicted by an adversary.
Battle Tested
This code has been used in production at Segment for several years, across a diverse array of projects. Trillions upon trillions of KSUIDs have been generated in some of Segment's most performance-critical, large-scale distributed systems.
Plays Well With Others
Designed to be integrated with other libraries, the KSUID
type
implements many standard library interfaces, including:
Stringer
database/sql.Scanner
anddatabase/sql/driver.Valuer
encoding.BinaryMarshal
andencoding.BinaryUnmarshal
encoding.TextMarshal
andencoding.TextUnmarshal
(encoding/json
friendly!)
Command Line Tool
This package comes with a command-line tool ksuid
, useful for
generating KSUIDs as well as inspecting the internal components of
existing KSUIDs. Machine-friendly output is provided for scripting
use cases.
Given a Go build environment, it can be installed with the command:
$ go install github.com/segmentio/ksuid/cmd/ksuid
CLI Usage Examples
Generate a KSUID
$ ksuid
0ujsswThIGTUYm2K8FjOOfXtY1K
Generate 4 KSUIDs
$ ksuid -n 4
0ujsszwN8NRY24YaXiTIE2VWDTS
0ujsswThIGTUYm2K8FjOOfXtY1K
0ujssxh0cECutqzMgbtXSGnjorm
0ujsszgFvbiEr7CDgE3z8MAUPFt
Inspect the components of a KSUID
$ ksuid -f inspect 0ujtsYcgvSTl8PAuAdqWYSMnLOv
REPRESENTATION:
String: 0ujtsYcgvSTl8PAuAdqWYSMnLOv
Raw: 0669F7EFB5A1CD34B5F99D1154FB6853345C9735
COMPONENTS:
Time: 2017-10-09 21:00:47 -0700 PDT
Timestamp: 107608047
Payload: B5A1CD34B5F99D1154FB6853345C9735
Generate a KSUID and inspect its components
$ ksuid -f inspect
REPRESENTATION:
String: 0ujzPyRiIAffKhBux4PvQdDqMHY
Raw: 066A029C73FC1AA3B2446246D6E89FCD909E8FE8
COMPONENTS:
Time: 2017-10-09 21:46:20 -0700 PDT
Timestamp: 107610780
Payload: 73FC1AA3B2446246D6E89FCD909E8FE8
Inspect a KSUID with template formatted inspection output
$ ksuid -f template -t '{{ .Time }}: {{ .Payload }}' 0ujtsYcgvSTl8PAuAdqWYSMnLOv
2017-10-09 21:00:47 -0700 PDT: B5A1CD34B5F99D1154FB6853345C9735
Inspect multiple KSUIDs with template formatted output
$ ksuid -f template -t '{{ .Time }}: {{ .Payload }}' $(ksuid -n 4)
2017-10-09 21:05:37 -0700 PDT: 304102BC687E087CC3A811F21D113CCF
2017-10-09 21:05:37 -0700 PDT: EAF0B240A9BFA55E079D887120D962F0
2017-10-09 21:05:37 -0700 PDT: DF0761769909ABB0C7BB9D66F79FC041
2017-10-09 21:05:37 -0700 PDT: 1A8F0E3D0BDEB84A5FAD702876F46543
Generate KSUIDs and output JSON using template formatting
$ ksuid -f template -t '{ "timestamp": "{{ .Timestamp }}", "payload": "{{ .Payload }}", "ksuid": "{{.String}}"}' -n 4
{ "timestamp": "107611700", "payload": "9850EEEC191BF4FF26F99315CE43B0C8", "ksuid": "0uk1Hbc9dQ9pxyTqJ93IUrfhdGq"}
{ "timestamp": "107611700", "payload": "CC55072555316F45B8CA2D2979D3ED0A", "ksuid": "0uk1HdCJ6hUZKDgcxhpJwUl5ZEI"}
{ "timestamp": "107611700", "payload": "BA1C205D6177F0992D15EE606AE32238", "ksuid": "0uk1HcdvF0p8C20KtTfdRSB9XIm"}
{ "timestamp": "107611700", "payload": "67517BA309EA62AE7991B27BB6F2FCAC", "ksuid": "0uk1Ha7hGJ1Q9Xbnkt0yZgNwg3g"}
OrNil functions
There are times when you are sure your ksuid is correct. But you need to get it from bytes or string and pass it it's to the structure. For this, there are OrNil functions that return ksuid.Nil on error and can be called directly in the structure.
Functions:
ParseOrNil()
FromPartsOrNil()
FromBytesOrNil()
An example of using the function without OrNil:
func getPosts(before, after []byte) {
b, err := ksuid.FromBytes(before)
if err != nil {
// handle error
}
a, err := ksuid.FromBytes(after)
if err != nil {
// handle error
}
sortOptions := SortOptions{Before: b, After: a}
}
It is much more convenient to do it like this:
func getPosts(before, after []byte) {
sortOptions := SortOptions{
Before: ksuid.FromBytesOrNil(before),
After: ksuid.FromBytesOrNil(after),
}
}
OrNil functions are also used in many other libraries:
- satori/go.uuid
- oklog/ulid (panic)
Implementations for other languages
- Python: svix-ksuid
- Python: cyksuid
- Ruby: ksuid-ruby
- Java: ksuid
- Java: ksuid-creator
- Rust: svix-ksuid
- dotNet: Ksuid.Net
- dotnet: KsuidDotNet
- Erlang: erl-ksuid
- Zig: zig-ksuid
License
ksuid source code is available under an MIT License.
Top Related Projects
Universally Unique Lexicographically Sortable Identifier (ULID) in Go
xid is a globally unique id generator thought for the web
UUID package for Go
Go package for UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
Collision-resistant ids optimized for horizontal scaling and performance.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot