A PostgreSQL extension that implements the ULID (Universally Unique Lexicographically Sortable Identifier) data type.
ULID is a 128-bit identifier designed to be:
- Sortable: Lexicographically sortable by timestamp
- Compact: 26-character string representation (vs 36 for UUID)
- URL-safe: Uses Crockford's Base32 encoding
- Monotonic: Sortable within the same millisecond
Format: 01ARZ3NDEKTSV4RRFFQ69G5FAV
- First 10 characters: 48-bit timestamp (milliseconds since Unix epoch)
- Last 16 characters: 80 bits of randomness
- Native PostgreSQL data type with full operator support
- B-tree and hash indexing support
- Optimized sorting with abbreviated key support
- Binary send/receive for efficient client-server communication
- Thread-safe random ULID generation
This is the standard way to install the extension into your existing PostgreSQL database.
- PostgreSQL 12+ (tested with PostgreSQL 12-18)
- PostgreSQL development headers (
postgresql-server-dev-allon Debian/Ubuntu) pg_configin your PATH- C compiler (gcc or clang)
# Install build dependencies (Debian/Ubuntu)
sudo apt-get install build-essential postgresql-server-dev-all
# Build and install the extension
make
sudo make installConnect to your database and run:
CREATE EXTENSION pg_ulid;If you need to install the extension files manually without using make install:
# 1. Build the shared library
make
# 2. Find your PostgreSQL directories
PG_LIBDIR=$(pg_config --pkglibdir)
PG_SHAREDIR=$(pg_config --sharedir)
# 3. Copy files to PostgreSQL directories
sudo cp ulid.so $PG_LIBDIR/
sudo cp pg_ulid.control $PG_SHAREDIR/extension/
sudo cp pg_ulid--0.1.0.sql $PG_SHAREDIR/extension/
# 4. Verify installation
ls -l $PG_LIBDIR/ulid.so
ls -l $PG_SHAREDIR/extension/pg_ulid*Then connect to your database and run:
CREATE EXTENSION pg_ulid;For development or testing, you can run a PostgreSQL instance with pg_ulid pre-installed:
# Build the Docker image
docker build -t postgres-pg_ulid .
# Run PostgreSQL with the extension available
docker run -d -p 5432:5432 postgres-pg_ulid
# Connect and create the extension
psql -h localhost -U postgres -c "CREATE EXTENSION pg_ulid;"-- Generate a random ULID
SELECT gen_random_ulid();
-- Output: 01HN64YSHFEB58ZAH8AV4HTTBT
-- Use as default value
CREATE TABLE users (
id ulid PRIMARY KEY DEFAULT gen_random_ulid(),
username TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);-- Insert ULID from string
INSERT INTO users (id, username)
VALUES ('01HN64YSHFEB58ZAH8AV4HTTBT'::ulid, 'alice');
-- ULIDs are sortable by creation time
SELECT id, username
FROM users
ORDER BY id ASC;-- B-tree index (supports <, <=, =, >=, >)
CREATE INDEX idx_users_id ON users (id);
-- Hash index (supports = only)
CREATE INDEX idx_users_id_hash ON users USING HASH (id);All standard comparison operators are supported:
SELECT * FROM users WHERE id < '01HN64YSHFEB58ZAH8AV4HTTBT'::ulid;
SELECT * FROM users WHERE id = '01HN64YSHFEB58ZAH8AV4HTTBT'::ulid;
SELECT * FROM users WHERE id >= '01HN64YSHFEB58ZAH8AV4HTTBT'::ulid;
SELECT * FROM users WHERE id <> '01HN64YSHFEB58ZAH8AV4HTTBT'::ulid;# Run regression tests using Docker
./test.sh
# Run code quality checks (requires clang-format and clang-tidy)
make -f Makefile.lint checkULIDs use Crockford's Base32 encoding (case-insensitive, excludes I, L, O, U to avoid confusion):
0123456789ABCDEFGHJKMNPQRSTVWXYZ
Stored as 16 bytes (128 bits):
- Bytes 0-5: 48-bit timestamp (milliseconds)
- Bytes 6-15: 80 bits of cryptographic randomness
- Uses PostgreSQL's
pg_strong_random()for cryptographically secure random generation - Abbreviated key optimization for fast sorting
- Efficient
memcmp-based comparison
This extension follows semantic versioning. Upgrade paths between versions:
- 0.1.x → 0.2.x: Planned minor version upgrades will provide automatic migration scripts
- Future upgrade scripts will be named:
ulid--0.1.0--0.2.0.sql
-- Check current version
SELECT extversion FROM pg_extension WHERE extname = 'pg_ulid';
-- Upgrade to latest version
ALTER EXTENSION pg_ulid UPDATE;
-- Upgrade to specific version
ALTER EXTENSION pg_ulid UPDATE TO '0.2.0';Downgrades are not supported. Always backup your database before upgrading.
This extension builds upon ideas and patterns from several sources:
- PostgreSQL Core: Data type implementation patterns, sort support strategies, and indexing structures (PostgreSQL License, Copyright PostgreSQL Global Development Group)
- ULID Specification: https://github.com/ulid/spec
- Crockford Base32: Encoding/decoding inspired by public domain ULID implementations, including https://github.com/skeeto/ulid-c (Unlicense)
MIT License - See LICENSE file for details
Contributions welcome! Please ensure:
- All tests pass (
./test.sh) - Code follows PostgreSQL C coding conventions
- New features include regression tests
- Source Code: https://github.com/dcbickfo/pg_ulid
- Issue Tracker: https://github.com/dcbickfo/pg_ulid/issues
- Documentation: doc/ulid.md