API Reference
Complete API documentation for all Kysera packages.
Kysera is a type-safe data access toolkit built on Kysely, not a traditional ORM. It provides composable patterns (Repository, DAL) and plugins for common database features, while maintaining Kysely's lightweight philosophy and full SQL control.
Kysera now features a Unified Execution Layer powered by @kysera/executor. This foundation package enables plugins to work seamlessly with both Repository and DAL patterns through query interception. Learn more about the architecture.
Architecture Overview
Kysera follows a layered architecture with @kysera/executor as the foundation:
┌─────────────────────────────────────────────────────┐
│ Application Layer (Repository / DAL Patterns) │
│ - @kysera/repository: Repository with validation │
│ - @kysera/dal: Functional query composition │
├─────────────────────────────────────────────────────┤
│ Plugin Layer (Query Interceptors & Extensions) │
│ - @kysera/soft-delete, @kysera/rls, etc. │
├─────────────────────────────────────────────────────┤
│ Unified Execution Layer │
│ - @kysera/executor: Plugin-aware Kysely wrapper │
├─────────────────────────────────────────────────────┤
│ Kysely Query Builder (peer dependency) │
└─────────────────────────────────────────────────────┘
Key Concepts:
- @kysera/executor wraps Kysely instances with plugin interception capabilities
- Plugins work with BOTH Repository and DAL patterns through the executor
- Query interceptors (e.g., soft-delete filters, RLS policies) apply automatically to all queries
- Repository extensions (e.g.,
repo.softDelete(),repo.restore()) work only with Repository pattern
Package Index
Core Packages
| Package | Description | Bundle Size |
|---|---|---|
| @kysera/core | Core utilities - errors, pagination, logger, types | ~8 KB |
| @kysera/executor | Foundation: Unified plugin execution layer | ~8 KB |
| @kysera/repository | Repository pattern with validation | ~12 KB |
| @kysera/dal | Functional Data Access Layer | ~7 KB |
Infrastructure Packages
| Package | Description | Bundle Size |
|---|---|---|
| @kysera/infra | Health checks, retry, circuit breaker, shutdown | ~12 KB |
| @kysera/debug | Query logging, profiling, SQL formatting | ~5 KB |
| @kysera/testing | Testing utilities and factories | ~6 KB |
| @kysera/migrations | Database migration system | ~12 KB |
Plugin Packages
| Package | Description | Bundle Size |
|---|---|---|
| @kysera/soft-delete | Soft delete functionality | ~4 KB |
| @kysera/timestamps | Automatic timestamp management | ~4 KB |
| @kysera/audit | Comprehensive audit logging | ~8 KB |
| @kysera/rls | Row-Level Security for multi-tenancy | ~10 KB |
@kysera/core
Core utilities including error handling, pagination, and logging.
| Module | Description |
|---|---|
| Errors | Multi-database error parsing |
| Pagination | Offset and cursor pagination |
| Logger | Configurable logging interface |
import { parseDatabaseError, paginate, consoleLogger } from '@kysera/core'
Package Dependencies
Understanding the dependency hierarchy helps you choose the right packages:
@kysera/executor (foundation - 0 dependencies)
│
├──> @kysera/dal (depends on executor)
│ └──> Used for: Functional queries with plugin support
│
├──> @kysera/repository (depends on executor + dal)
│ └──> Used for: Repository pattern with validation and plugin methods
│
└──> Plugin packages (use executor's Plugin interface)
├──> @kysera/soft-delete (query interceptor + repository extensions)
├──> @kysera/rls (query interceptor + repository extensions)
├──> @kysera/timestamps (repository extensions only)
└──> @kysera/audit (repository extensions only)
@kysera/core (standalone - 0 dependencies)
└──> Used by: All packages for errors, pagination, logging
Plugin Capabilities:
| Plugin Feature | Works with Repository | Works with DAL |
|---|---|---|
Query Interceptors (interceptQuery) | ✅ Yes | ✅ Yes (via executor) |
Repository Extensions (extendRepository) | ✅ Yes | ❌ No |
Examples:
@kysera/soft-delete: Automatic filtering works in both;repo.softDelete()method only in Repository@kysera/rls: RLS policies work in both; validation methods only in Repository@kysera/timestamps: Repository only (no query interception needed)@kysera/audit: Repository only (no query interception needed)
@kysera/executor
Foundation package - Unified plugin execution layer enabling plugins to work with both Repository and DAL patterns. Full Documentation →
import { createExecutor, isKyseraExecutor, getPlugins, getRawDb } from '@kysera/executor'
Core Concept: Wraps Kysely instances with plugin interception, allowing automatic query modification (filtering, policies) before execution while maintaining full type safety.
Key Features:
- Zero overhead when no interceptor plugins are registered
- Automatic plugin validation (conflicts, dependencies, circular deps)
- Transaction propagation - plugins automatically work in transactions
- Plugin priority and dependency resolution
getRawDb()for bypassing interceptors when needed
Quick Example:
import { createExecutor } from '@kysera/executor'
import { softDeletePlugin } from '@kysera/soft-delete'
const executor = await createExecutor(db, [softDeletePlugin()])
// Automatic soft-delete filtering
const users = await executor.selectFrom('users').selectAll().execute()
// Works in transactions
await executor.transaction().execute(async (trx) => {
// Plugins automatically applied
const user = await trx.selectFrom('users').where('id', '=', 1).executeTakeFirst()
})
@kysera/repository
Type-safe repository pattern implementation with full plugin support. Full Documentation →
| Module | Description |
|---|---|
| Factory | Repository factory functions |
| Validation | Validation utilities |
| Types | Type definitions |
import { createRepositoryFactory, createORM, withPlugins } from '@kysera/repository'
Plugin Integration: Uses @kysera/executor internally, supporting both query interceptors (interceptQuery) and repository extensions (extendRepository).
@kysera/dal
Functional Data Access Layer for composable queries with query interceptor support via KyseraExecutor. Full Documentation →
import { createQuery, withTransaction, createContext, compose, parallel } from '@kysera/dal'
Plugin Integration: Works with @kysera/executor to support query interceptor plugins (soft-delete, RLS, etc.). Repository extension plugins are not available in DAL.
@kysera/infra
Infrastructure utilities for production applications.
import {
checkDatabaseHealth,
HealthMonitor,
withRetry,
CircuitBreaker,
registerShutdownHandlers
} from '@kysera/infra'
@kysera/debug
Debug and profiling utilities.
import { withDebug, QueryProfiler, formatSQL, highlightSQL } from '@kysera/debug'
@kysera/testing
Testing utilities for Kysera applications.
import {
testInTransaction,
createFactory,
cleanDatabase,
seedDatabase
} from '@kysera/testing'
@kysera/migrations
Database migration system.
import {
createMigration,
createMigrationRunner,
runMigrations,
getMigrationStatus
} from '@kysera/migrations'
Plugin Packages
@kysera/soft-delete
Mark records as deleted without removing them.
import { softDeletePlugin } from '@kysera/soft-delete'
const orm = await createORM(db, [
softDeletePlugin({ deletedAtColumn: 'deleted_at' })
])
// Methods added: softDelete, restore, hardDelete, findWithDeleted, etc.
@kysera/timestamps
Automatic timestamp management.
import { timestampsPlugin } from '@kysera/timestamps'
const orm = await createORM(db, [
timestampsPlugin() // Zero config!
])
// created_at and updated_at are set automatically
@kysera/audit
Comprehensive audit logging.
import { auditPlugin } from '@kysera/audit'
const orm = await createORM(db, [
auditPlugin({
getUserId: () => currentUser?.id,
captureOldValues: true,
captureNewValues: true
})
])
// Methods added: getAuditHistory, getAuditLog, restoreFromAudit
@kysera/rls
Row-Level Security for multi-tenant applications.
import { rlsPlugin, defineRLSSchema, filter, allow, rlsContext } from '@kysera/rls'
const rlsSchema = defineRLSSchema({
posts: {
policies: [
filter('read', ctx => ({ tenant_id: ctx.auth.tenantId })),
allow(['update', 'delete'], ctx => ctx.auth.userId === ctx.row?.author_id)
]
}
})
const orm = await createORM(db, [rlsPlugin({ schema: rlsSchema })])
// All queries automatically filtered by tenant
await rlsContext.runAsync({ auth: { userId: 1, tenantId: 'acme', roles: [] } }, async () => {
const posts = await postRepo.findAll() // Filtered by tenant_id = 'acme'
})
Quick Reference
Creating a Repository
import { createRepositoryFactory } from '@kysera/repository'
import { z } from 'zod'
const factory = createRepositoryFactory(db)
const userRepo = factory.create({
tableName: 'users' as const,
mapRow: (row) => ({
id: row.id,
email: row.email,
name: row.name,
createdAt: row.created_at
}),
schemas: {
create: z.object({
email: z.string().email(),
name: z.string().min(1)
})
}
})
Using Plugins (Unified Approach)
With the Unified Execution Layer, create an executor with plugins that work across both Repository and DAL:
import { createExecutor } from '@kysera/executor'
import { createORM } from '@kysera/repository'
import { softDeletePlugin } from '@kysera/soft-delete'
import { timestampsPlugin } from '@kysera/timestamps'
import { auditPlugin } from '@kysera/audit'
import { rlsPlugin } from '@kysera/rls'
// Create executor with query interceptor plugins
const executor = await createExecutor(db, [
rlsPlugin({ schema: rlsSchema }), // RLS policies (query interceptor)
softDeletePlugin() // Soft-delete filter (query interceptor)
])
// createORM creates a plugin container (repository manager), not a traditional ORM
// It gets both query interceptors + extension methods
const orm = await createORM(executor, [
timestampsPlugin(), // Repository extension only
auditPlugin({ // Repository extension only
getUserId: () => currentUser?.id
})
])
// DAL pattern: Gets query interceptors only
import { createQuery } from '@kysera/dal'
const getUsers = createQuery((ctx) =>
ctx.db.selectFrom('users').selectAll().execute()
)
// RLS and soft-delete filters automatically applied!
const users = await getUsers(executor)
Key Points:
- Query interceptor plugins (soft-delete, RLS) → Add to executor
- Repository extension plugins (timestamps, audit) → Add to
createORM(plugin container) - Both patterns share the same query interceptors for consistent behavior
createORMis a plugin container/repository manager, not a traditional ORM
Error Handling
import { parseDatabaseError, UniqueConstraintError, ForeignKeyError } from '@kysera/core'
try {
await userRepo.create({ email: 'existing@example.com', name: 'Test' })
} catch (rawError) {
const error = parseDatabaseError(rawError, 'postgres')
if (error instanceof UniqueConstraintError) {
console.log(`Duplicate value in columns: ${error.columns.join(', ')}`)
}
if (error instanceof ForeignKeyError) {
console.log(`Foreign key violation: ${error.constraint}`)
}
}
Health Checks
import { checkDatabaseHealth, HealthMonitor } from '@kysera/infra'
// One-time check
const health = await checkDatabaseHealth(db)
console.log(health.status) // 'healthy' | 'degraded' | 'unhealthy'
// Continuous monitoring
const monitor = new HealthMonitor(db, { intervalMs: 30000 })
monitor.start((result) => {
if (result.status !== 'healthy') {
alerting.send('Database health issue', result)
}
})
Pagination
import { paginate, paginateCursor } from '@kysera/core'
// Offset pagination
const page = await paginate(
db.selectFrom('posts').selectAll(),
{ page: 1, limit: 20 }
)
// { items: [...], total: 100, page: 1, limit: 20, totalPages: 5 }
// Cursor pagination
const result = await paginateCursor(
db.selectFrom('posts').selectAll(),
{
orderBy: [{ column: 'created_at', direction: 'desc' }],
limit: 20,
cursor: previousCursor
}
)
// { items: [...], nextCursor: {...}, hasMore: true }
Transactions with Plugins
Plugins automatically propagate through transactions:
import { createExecutor } from '@kysera/executor'
import { softDeletePlugin } from '@kysera/soft-delete'
import { createORM } from '@kysera/repository'
import { withTransaction, createQuery } from '@kysera/dal'
// Create executor with plugins
const executor = await createExecutor(db, [softDeletePlugin()])
// Repository pattern - plugins in transactions
const orm = await createORM(executor, [])
await orm.transaction(async (ctx) => {
const userRepo = orm.createRepository(createUserRepository)
const user = await userRepo.create({ email: 'new@example.com', name: 'New User' })
// Soft-delete filter applied within transaction
const activeUsers = await userRepo.findAll()
})
// DAL pattern - plugins in transactions
const getUsers = createQuery((ctx) =>
ctx.db.selectFrom('users').selectAll().execute()
)
await withTransaction(executor, async (ctx) => {
// Soft-delete filter automatically applied
const users = await getUsers(ctx)
// Both operations commit or roll back together
})
// Repository factory pattern
import { createRepositoriesFactory } from '@kysera/repository'
const createRepos = createRepositoriesFactory({
users: (executor) => createUserRepository(executor),
posts: (executor) => createPostRepository(executor)
})
await executor.transaction().execute(async (trx) => {
const repos = createRepos(trx)
// All queries inherit plugins from executor
const user = await repos.users.create({ email: 'new@example.com', name: 'New User' })
await repos.posts.create({ title: 'First Post', userId: user.id })
})
Version Compatibility
| Package | Version | Kysely | Node.js | Bun | Deno |
|---|---|---|---|---|---|
| @kysera/core | 0.6.1 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/executor | 0.7.0 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/repository | 0.7.0 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/dal | 0.7.0 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/infra | 0.6.1 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/debug | 0.6.1 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/testing | 0.6.1 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/migrations | 0.6.1 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/soft-delete | 0.7.0 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/timestamps | 0.6.1 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/audit | 0.6.1 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
| @kysera/rls | 0.7.0 | >=0.28.8 | >=20 | >=1.0 | >=1.40 |
Database Support
| Feature | PostgreSQL | MySQL | SQLite |
|---|---|---|---|
| RETURNING clause | Native | Emulated | Native |
| JSONB columns | Native | JSON type | TEXT |
| Partial indexes | Supported | Limited | Supported |
| Row-level security | Native + App | App-level | App-level |
| Boolean type | true/false | 1/0 | 1/0 |