@owpz/prisma-ksuid
v25.9.20
Published
Prisma Client extension for generating K-Sortable Unique IDs (KSUIDs)
Downloads
74
Maintainers
Readme
@owpz/prisma-ksuid
A production-ready Prisma Client extension for generating K-Sortable Unique IDs (KSUIDs) as primary keys in your database models. Built on @owpz/ksuid for 100% Go compatibility and high performance.
📋 Project Links
- Contributing Guidelines - How to contribute, report issues, and submit pull requests
- Security Policy - How to report security vulnerabilities
- GitHub Issues - Report bugs or request features
- NPM Package - Install the package
Important:
- Requires Prisma 4.16.0+ - This is when the extension API (
$extends) was introduced- For Prisma 6.14.0+ - The extension API is mandatory as middleware support (
$use) was completely removed
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.
Key advantages over UUIDs:
- Time-sortable: KSUIDs can be sorted chronologically, making them ideal for databases
- Shorter: More compact than UUIDs when encoded in base62 (27 vs 36 characters)
- URL-friendly: No special characters, making them safe for URLs and file names
- Prefixable: Can be prefixed with model-specific identifiers for better readability
For detailed KSUID documentation, see @owpz/ksuid.
Quick Start
Install the package:
npm install @owpz/prisma-ksuidSet up your Prisma schema with string IDs:
model User { id String @id @default(dbgenerated()) @map("id") name String email String @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }Configure the extension:
import { PrismaClient } from "@prisma/client"; import { createKsuidExtension } from "@owpz/prisma-ksuid"; const prisma = new PrismaClient().$extends( createKsuidExtension({ prefixMap: { User: "usr_" }, }), );
Migration from Middleware
If you're upgrading from an older version that used createKsuidMiddleware:
Before (Prisma < 6.14.0 with middleware)
import { createKsuidMiddleware } from "@owpz/prisma-ksuid";
const prisma = new PrismaClient();
prisma.$use(createKsuidMiddleware({ prefixMap }));After (Prisma 4.16.0+ with extensions)
import { createKsuidExtension } from "@owpz/prisma-ksuid";
const prisma = new PrismaClient().$extends(createKsuidExtension({ prefixMap }));Note:
createKsuidMiddlewareis still exported for backward compatibility but will show a deprecation warning. It won't work with Prisma 6.14.0+ since$usehas been removed.
Advanced Usage
Multiple models with prefixes
import { PrismaClient } from "@prisma/client";
import { createKsuidExtension } from "@owpz/prisma-ksuid";
const prefixMap = {
User: "usr_",
PaymentIntent: "pi_",
Customer: "cus_",
Post: "post_",
Comment: "cmt_",
};
const prisma = new PrismaClient().$extends(createKsuidExtension({ prefixMap }));
export default prisma;With fallback prefix function
const prefixMap = {
User: "usr_",
Post: "post_",
};
const prefixFn = (model: string) => model.slice(0, 3).toLowerCase() + "_";
const prisma = new PrismaClient().$extends(
createKsuidExtension({
prefixMap,
prefixFn, // Used for models not in prefixMap
}),
);With custom primary key fields
// For models using different primary key field names
const prisma = new PrismaClient().$extends(
createKsuidExtension({
prefixMap: {
User: "usr_",
Session: "sess_",
},
primaryKeyField: (model) => {
// Session model uses 'token' as primary key
if (model === "Session") return "token";
// Others use default 'id'
return "id";
},
}),
);Working with upserts
// The extension generates KSUIDs for the create portion of upserts
const user = await prisma.user.upsert({
where: { email: "[email protected]" },
update: { name: "Updated Name" },
create: {
email: "[email protected]",
name: "New User",
// ID will be generated with usr_ prefix
},
});Using createManyAndReturn (Prisma 6+)
// Create multiple records and get them back with generated IDs
const users = await prisma.user.createManyAndReturn({
data: [
{ email: "[email protected]", name: "User 1" },
{ email: "[email protected]", name: "User 2" },
// IDs will be generated with usr_ prefix
],
});
console.log(users);
// [
// { id: 'usr_2KjMLq...', email: '[email protected]', ... },
// { id: 'usr_2KjMLr...', email: '[email protected]', ... }
// ]Using the KSUID generator directly
⚠️ DEPRECATED: Direct usage of
generateKSUIDfrom this package is deprecated and will be removed in version v25.8 or greater. Use @owpz/ksuid directly for standalone KSUID generation.
// ❌ Deprecated - will be removed in future versions
import { generateKSUID } from "@owpz/prisma-ksuid";
// ✅ Recommended - use the core library instead
import { KSUID } from "@owpz/ksuid";
// Generate KSUIDs with the core library
const userId = "usr_" + KSUID.random().toString();
console.log(userId); // usr_1xGVYLMNZO2PfHqPnRlwu5NFNMB
const id = KSUID.random().toString();
console.log(id); // 1xGVYLMNZO2PfHqPnRlwu5NFNMBFeatures
This extension supports all Prisma operations that create new records:
- ✅ Basic creates:
prisma.user.create() - ✅ Nested creates: Creating related records in a single operation
- ✅ Batch creates:
prisma.user.createMany() - ✅ Batch creates with return:
prisma.user.createManyAndReturn()(Prisma 6+) - ✅ Upsert operations:
prisma.user.upsert()(generates ID for create portion) - ✅ Nested upserts: Handles nested
upsertin relations - ✅ Connect or create: Nested
connectOrCreateoperations - ✅ Transaction support: Works within
prisma.$transaction() - ✅ Flexible prefixing: Map-based or function-based prefix generation
- ✅ Custom primary keys: Support for non-
idfields and composite keys - ✅ DMMF metadata: Uses Prisma's metadata for accurate relation resolution
- ✅ Type safety: Full TypeScript support with proper typing
Limitations
Due to Prisma extension constraints, this library cannot handle:
- ❌ Raw queries:
prisma.$executeRaw()andprisma.$queryRaw()bypass extensions - ❌ Database-level operations: Direct SQL INSERTs, stored procedures, or triggers
- ❌ Schema-level defaults: Cannot override
@default(cuid())or@default(uuid())in schema - ❌ External inserts: Records created outside of Prisma Client (e.g., database admin tools)
- ❌ Retroactive ID generation: Cannot generate KSUIDs for existing records
API Reference
createKsuidExtension(options)
Creates a Prisma Client extension that automatically generates KSUIDs for models during create operations.
Parameters
options(object, required): Configuration object with the following properties:
| Property | Type | Required | Default | Description |
|----------|------|----------|---------|-------------|
| prefixMap | Record<string, string> | Yes | - | Object mapping model names to their prefix strings |
| prefixFn | (model: string) => string | No | undefined | Fallback function to generate prefixes for models not in prefixMap |
| processNestedCreates | boolean | No | true | Enable/disable processing of nested create operations |
| primaryKeyField | string \| ((model: string) => string) | No | "id" | Specify the primary key field name per model |
Returns
Returns a Prisma extension function compatible with prisma.$extends().
Example Usage
import { PrismaClient } from "@prisma/client";
import { createKsuidExtension } from "@owpz/prisma-ksuid";
const prisma = new PrismaClient().$extends(
createKsuidExtension({
prefixMap: {
User: "usr_",
Post: "post_",
Comment: "cmt_"
},
prefixFn: (model) => model.slice(0, 3).toLowerCase() + "_",
processNestedCreates: true,
primaryKeyField: "id"
})
);Supported Operations
The extension automatically generates KSUIDs for the following Prisma operations:
Basic Operations
create: Creates a single record with generated KSUIDconst user = await prisma.user.create({ data: { email: "[email protected]", name: "John Doe" } }); // Returns: { id: "usr_2KjMLq...", email: "...", name: "..." }createMany: Creates multiple records with generated KSUIDsawait prisma.user.createMany({ data: [ { email: "[email protected]", name: "User 1" }, { email: "[email protected]", name: "User 2" } ] });createManyAndReturn(Prisma 6+): Creates multiple records and returns themconst users = await prisma.user.createManyAndReturn({ data: [ { email: "[email protected]", name: "User 1" }, { email: "[email protected]", name: "User 2" } ] }); // Returns array of created users with generated IDs
Advanced Operations
upsert: Creates with KSUID if record doesn't existconst user = await prisma.user.upsert({ where: { email: "[email protected]" }, update: { name: "Updated Name" }, create: { email: "[email protected]", name: "New User" } });Nested Creates: Generates KSUIDs for related records
const user = await prisma.user.create({ data: { email: "[email protected]", posts: { create: [ { title: "First Post" }, // Gets post_ prefix { title: "Second Post" } // Gets post_ prefix ] } } });Connect or Create: Generates KSUID for create portion
const post = await prisma.post.create({ data: { title: "New Post", author: { connectOrCreate: { where: { email: "[email protected]" }, create: { email: "[email protected]", name: "New User" } } } } });
generateKSUID(prefix?) ⚠️ DEPRECATED
Deprecated: Use @owpz/ksuid directly instead.
Generates a K-Sortable Unique ID (KSUID).
Parameters
prefix(string, optional): A string prefix to add to the generated KSUID. Default is an empty string.
Returns
Returns a string containing the generated KSUID with the optional prefix.
Migration Guide
// ❌ Old way (deprecated)
import { generateKSUID } from "@owpz/prisma-ksuid";
const id = generateKSUID("usr_");
// ✅ New way (recommended)
import { KSUID } from "@owpz/ksuid";
const id = "usr_" + KSUID.random().toString();🔌 Database Integration
This extension integrates seamlessly with Prisma's ecosystem:
Core Prisma Features
- Full TypeScript support with proper type inference
- Transaction support for consistent ID generation
- Migration compatible with existing string primary keys
- Works with all databases Prisma supports (PostgreSQL, MySQL, SQLite, etc.)
License
This package is released under the MIT License.
Copyright (c) 2025 Apex Innovations, Inc.
