Primary Keys and Identifiers
Configure custom primary keys, UUIDs, and auto-minted column IDs.
Brick-TS uses whatever primary key your Drizzle table defines: autoincrement integers, UUIDs, or custom prefixed string identifiers minted with $defaultFn().
Minimal Example
Define an auto-minted UUID primary key and register it with the resource:
import {
defineDatabase,
defineService,
sqliteTable,
text,
} from "@brickkit/core";
import { crud } from "@brickkit/crud";
export const items = sqliteTable("items", {
// Auto-minted UUID primary key
id: text("id")
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
name: text("name").notNull(),
});
const database = defineDatabase({ tables: { items } });
export const itemsService = defineService("items", { database });
// Register resource identity using items.id
export const itemResource = itemsService
.resource({
name: "item",
table: items,
id: items.id, // Optional here: items has a single primary key
})
.use(
crud({
access: "public",
fields: {
id: { read: true, filter: ["eq", "in"] },
name: { read: true, create: true, update: true },
},
}),
);Schema
These columns match the Drizzle tables in the example. Defaults marked as application defaults run in Drizzle, rather than in SQL.
Table Name: items
| Field | Type | Description |
|---|---|---|
id | text | Row identifier. PK Default: crypto.randomUUID() (application) |
name | text | Display name. |
Table Name: documents
| Field | Type | Description |
|---|---|---|
id | text | Row identifier. PK Default: crypto.randomUUID() (application) |
title | text | Display title. |
Table Name: users
| Field | Type | Description |
|---|---|---|
id | text | Row identifier. PK Default: mintId("usr") (application) |
name | text | Display name. |
Table Name: logs
| Field | Type | Description |
|---|---|---|
id | integer | Row identifier. PK Default: autoincrement |
message | text | Log message. |
Supported Primary Key Strategies
Drizzle column builders define primary key generation strategies:
1. Auto-Minted UUIDs
Generates random RFC 4122 UUID strings on row creation:
export const documents = sqliteTable("documents", {
id: text("id")
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
title: text("title").notNull(),
});2. Prefixed Identifiers (Stripe-Style)
Prefix IDs with entity tags (e.g. usr_..., inv_...) to improve readability and debugging:
function mintId(prefix: string): string {
return `${prefix}_${crypto.randomUUID().replace(/-/g, "").slice(0, 16)}`;
}
export const users = sqliteTable("users", {
id: text("id")
.primaryKey()
.$defaultFn(() => mintId("usr")),
name: text("name").notNull(),
});3. Autoincrement Integers
Standard sequential integer identifiers:
import { integer, sqliteTable, text } from "@brickkit/core";
export const logs = sqliteTable("logs", {
id: integer("id").primaryKey({ autoIncrement: true }),
message: text("message").notNull(),
});When using integer keys, Brick automatically types action parameters such as id in item.get and item.update as number.
Resource Identity Registration
service.resource() takes an optional id column. If you omit it, Brick uses the table's primary key when the table has exactly one primary-key column. Pass id explicitly when the table has no single primary key (for example a composite key) or when you want lookups to use a different unique column; the column must belong to the resource's table, otherwise resource() throws Resource '<name>' requires an id column belonging to its table.
const product = service
.resource({
name: "product",
table: productsTable,
id: productsTable.id, // Column CRUD uses for get/update/delete lookups
})
.use(crud({ access: "public", fields: {/* ... */} }));The CRUD plugin uses this column for single-record operations, and types id from the column's data type:
product.get({ input: { id: "prod_1" } })product.update({ input: { id: "prod_1", data: { name: "New Name" } } })product.delete({ input: { id: "prod_1" } })