β‘οΈ Ultra-fast ULID (Universally Unique Lexicographically Sortable Identifier) generator for React Native
Built with JSI (JavaScript Interface) and C++ for maximum performance. Features monotonic generation with thread-local state for guaranteed ID ordering. Supports both New Architecture (Fabric + TurboModules) and Old Architecture on iOS and Android.
π 500x faster than JavaScript | π Monotonic | π¦ Zero dependencies
500x faster than pure JavaScript implementations!
Comparison performed against the official ulid/javascript package.
| Implementation | Time (1000 iterations) | Performance |
|---|---|---|
| react-native-ulid-jsi (JSI/C++) | 0.17ms | β‘οΈ 500x faster |
| Pure JavaScript (ulid package) | 83.62ms | π Baseline |
react-native-ulid-jsi β 0.17ms
JavaScript ULID ββββββββββββββββββββββββββββββββββββββββββββββββββ 83.62ms
ββββββββββββββββββββββββββββββββββββββββββββββββββ
500x performance gain
Benchmark performed on iPhone 16 Pro with production build
- Zero Bridge Overhead: Direct JSI binding to C++ (no serialization)
- Native Random Generation: Platform-specific secure random APIs
- Optimized Encoding: Hand-tuned Base32 encoding in C++
- Thread-local State: No synchronization overhead for monotonic generation
- Minimal Allocations: Stack-allocated buffers, no heap fragmentation
import { ulid } from 'react-native-ulid-jsi';
const iterations = 1000;
const start = performance.now();
for (let i = 0; i < iterations; i++) {
ulid();
}
const end = performance.now();
console.log(`Generated ${iterations} ULIDs in ${(end - start).toFixed(2)}ms`);
// Output: Generated 1000 ULIDs in 0.17ms- β‘οΈ Lightning Fast - JSI + C++ implementation for native performance
- ποΈ New Architecture Ready - Full support for React Native's new architecture (Fabric + TurboModules)
- π Backward Compatible - Works seamlessly with old architecture
- π± Cross Platform - iOS and Android support
- π― Type Safe - Full TypeScript support
- πͺΆ Lightweight - Zero dependencies, pure C++ implementation
- π Monotonic Generation - Guarantees increasing IDs even within the same millisecond
- β±οΈ Timestamp Encoded - Contains creation timestamp (first 48 bits)
- π² Cryptographically Secure - Platform-native secure random generation
- iOS:
SecRandomCopyBytes(Security Framework) - Android: getrandom when available, falls back to /dev/urandom
- iOS:
- π€ Crockford's Base32 - Excludes ambiguous characters (I, L, O, U)
npm install react-native-ulid-jsior with yarn:
yarn add react-native-ulid-jsicd ios && pod installNo additional steps required. Gradle will handle everything automatically.
import { ulid } from 'react-native-ulid-jsi';
// Generate a new ULID
const id = ulid();
console.log(id); // 01ARZ3NDEKTSV4RRFFQ69G5FAV
// Generate multiple ULIDs - they will be monotonically increasing
const id1 = ulid(); // 01HGW4Z6C8ABCDEFGHIJKLMNOP
const id2 = ulid(); // 01HGW4Z6C8ABCDEFGHIJKLMNPQ (guaranteed > id1)
const id3 = ulid(); // 01HGW4Z6C8ABCDEFGHIJKLMNPR (guaranteed > id2)import { ulid } from 'react-native-ulid-jsi';
// Generate ULID with custom timestamp (milliseconds since epoch)
const timestamp = Date.now();
const id = ulid(timestamp);
console.log(id); // 01ARZ3NDEKTSV4RRFFQ69G5FAVimport { isValid } from 'react-native-ulid-jsi';
const id = '01ARZ3NDEKTSV4RRFFQ69G5FAV';
const valid = isValid(id);
console.log(valid); // trueimport { decodeTime } from 'react-native-ulid-jsi';
const id = '01ARZ3NDEKTSV4RRFFQ69G5FAV';
const timestamp = decodeTime(id);
console.log(timestamp); // 1469918176385
console.log(new Date(timestamp)); // 2016-07-31T04:42:56.385ZGenerates a new ULID.
Parameters:
seedTime(optional): Custom timestamp in milliseconds since Unix epoch. If not provided, uses current time.
Returns: A 26-character ULID string.
Example:
const id1 = ulid(); // Uses current time
const id2 = ulid(1469918176385); // Uses custom timeValidates whether a string is a valid ULID.
Parameters:
id: String to validate
Returns: true if valid ULID, false otherwise.
Example:
isValid('01ARZ3NDEKTSV4RRFFQ69G5FAV'); // true
isValid('invalid-id'); // falseExtracts the timestamp from a ULID.
Parameters:
id: Valid ULID string
Returns: Timestamp in milliseconds since Unix epoch.
Example:
const timestamp = decodeTime('01ARZ3NDEKTSV4RRFFQ69G5FAV');
console.log(new Date(timestamp)); // Original creation timeThis library is built to support both React Native architectures:
β
Fully supported with JSI direct bindings
β
Zero overhead JavaScript
β Fully supported with JSI module installation β Same performance benefits β No breaking changes required
The library automatically detects and works with the architecture your app is using.
ULID (Universally Unique Lexicographically Sortable Identifier) is a better alternative to UUID for many use cases:
- Sortable: Unlike UUIDs, ULIDs are lexicographically sortable
- Timestamp: Contains a timestamp component (first 48 bits)
- Compact: 26 characters vs UUID's 36 characters
- URL-safe: Uses Crockford's base32 encoding
- Case-insensitive: Easy to use in various contexts
- No special characters: Just alphanumeric characters
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
Timestamp Randomness
(48 bits) (80 bits)
This library implements monotonic ULID generation, ensuring that IDs are always increasing even when generated within the same millisecond.
- Same timestamp: If multiple ULIDs are generated in the same millisecond, the random component is incremented instead of generating new random bytes
- Overflow protection: If the random component overflows, a new random value is generated
- Time progression: When time advances, a fresh random value is used
// Without monotonic (pure random):
const id1 = ulid(); // 01HGW4Z6C8ABCDEFGHIJKLMNOP
const id2 = ulid(); // 01HGW4Z6C8ZYXWVUTSRQPONMLK β Not guaranteed to be > id1
// With monotonic (this library):
const id1 = ulid(); // 01HGW4Z6C8ABCDEFGHIJKLMNOP
const id2 = ulid(); // 01HGW4Z6C8ABCDEFGHIJKLMNPQ β
Always > id1Benefits:
- β Database indexes work optimally (B-tree friendly)
- β No collisions within same millisecond
- β Guaranteed sortability
- β Better for distributed systems
- Database IDs: Sortable by creation time without separate timestamp field
- Distributed Systems: Generate unique IDs without coordination
- API Resources: URL-safe identifiers for REST APIs
- Event Sourcing: Time-ordered events with unique identifiers
- Logging: Sortable log entry identifiers
- File Names: Unique, sortable file names
- Implementation: Pure C++ with JSI (JavaScript Interface) bindings
- Monotonic Generation: Thread-local state ensures IDs increment even within same millisecond
- Thread Safety: Thread-local storage per thread, no locks or mutexes needed
- Random Generation (with automatic fallback):
- iOS:
SecRandomCopyBytes(Security Framework) - Android: getrandom when available, falls back to /dev/urandom
- Last resort:
std::random_device(other platforms)
- iOS:
- Encoding: Crockford's Base32 (0-9, A-Z excluding I, L, O, U)
- Memory: Minimal allocation, optimized for mobile devices
- Dependencies: Zero - pure C++ standard library
- Bundle Size: Native module only, zero JavaScript bundle impact
- Platforms: iOS 12+, Android API 21+
| Feature | react-native-ulid-jsi | JavaScript ULID |
|---|---|---|
| Performance | β‘οΈ 0.17ms (1000 ops) | π 83.62ms (1000 ops) |
| Speed Improvement | 500x faster | Baseline |
| Implementation | C++ / JSI | JavaScript |
| Monotonic | β Thread-local | |
| Architecture Support | New + Old | N/A |
| Secure Random | β Platform native | |
| Bundle Impact | Native only (0 KB JS) | +5-10 KB bundle |
| Dependencies | Zero | Varies |
Contributions are welcome! Please read our contributing guidelines and code of conduct.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See CONTRIBUTING.md for detailed development setup.
MIT Β© Alex Shumihin
If this project helped you, please give it a βοΈ!
Made with β€οΈ using create-react-native-library