Client extensions
Attach app-specific helpers and shared values to a Better Drizzle client with extends().
client.extends(...) is the lightest way to add application-specific helpers or shared values to a Better Drizzle client.
Object form
Use the object form for static values:
const client = better(db, { schema }).extends({
tenantScope: 'public',
});
console.log(client.tenantScope);Callback form
Use the callback form when the helper needs the bound client instance:
const client = better(db, { schema }).extends((client) => ({
findByIdOrName(idOrName: number | string) {
return typeof idOrName === 'number'
? client.users.findFirst({ where: { id: idOrName } })
: client.users.findFirst({ where: { name: idOrName } });
},
}));
const user = await client.findByIdOrName('Alice');The callback form is the safer default when the helper needs to call back into the client, because it closes over the already bound instance.
Derived clients keep the extension
Extensions are reapplied to future $withContext() clones and transaction clients:
const base = client.extends((client) => ({
findById(id: number) {
return client.users.findFirst({ where: { id } });
},
}));
const scoped = base.$withContext({ requestId: 'req-1' });
await scoped.findById(1);
await base.transaction(async (tx) => {
await tx.findById(1);
});Conflicts fail fast
extends() cannot override built-in client methods, table delegates, plugin
client extensions, or keys added by an earlier extends() call.
When to use extends vs plugins
Use extends() when:
- the helper is app-specific
- the behavior only needs client-level helpers or shared values
- you do not need transforms, lifecycle hooks, or typed operation args
Reach for a plugin when the behavior needs to change repository operations globally, attach model-level helpers, or participate in hook/transform flow.