Database Adapters
Connect Dyrected to your preferred database.
Dyrected is database-agnostic. Choose the adapter that fits your infrastructure and pass it to defineConfig as db. All adapters implement the same DatabaseAdapter interface, so your application code never changes when you switch.
On Dyrected Cloud, no database adapter is needed. The database is fully managed — just omit the
dbfield from your config and rundyrected push. Learn more →
Supported Adapters
PostgreSQL — @dyrected/db-postgres (Recommended)
Best choice for production. Uses postgres (node-postgres) under the hood with full JSONB support.
import { PostgresAdapter } from '@dyrected/db-postgres'
export default defineConfig({
db: new PostgresAdapter({
url: process.env.DATABASE_URL, // postgresql://user:pass@host:5432/db
}),
})Connection pool config:
new PostgresAdapter({
url: process.env.DATABASE_URL,
max: 10, // maximum pool size (default: 10)
idle: 20_000, // ms before an idle connection is closed (default: 20s)
connect: 30, // connection timeout in seconds (default: 30)
})Vercel / serverless: Set
max: 1to avoid exhausting the connection pool across short-lived function instances.
SQLite — @dyrected/db-sqlite
Great for local development, single-server deployments, and edge environments. Uses better-sqlite3.
import { SqliteAdapter } from '@dyrected/db-sqlite'
export default defineConfig({
db: new SqliteAdapter({
filename: 'dyrected.db', // path to the SQLite file
}),
})Note: SQLite is not suitable for serverless deployments (Vercel, Cloudflare Workers) because the filesystem is ephemeral. Use PostgreSQL instead.
MongoDB — @dyrected/db-mongodb
For document-based workloads. Uses the official MongoDB Node.js driver.
import { MongoAdapter } from '@dyrected/db-mongodb'
export default defineConfig({
db: new MongoAdapter({
url: process.env.MONGODB_URI, // mongodb+srv://...
}),
})MySQL — @dyrected/db-mysql (coming soon)
MySQL / PlanetScale support is planned. The package is reserved but not yet implemented. Use PostgreSQL or SQLite in the meantime.
Schema sync
On startup, Dyrected calls db.sync() to ensure the required tables or collections exist. This is non-destructive — it creates missing tables but never drops or alters existing columns.
// Called automatically by createDyrectedApp(). No manual call needed.
await config.db.sync(config.collections, config.globals)Production note:
sync()is safe to run on every deploy. It is equivalent toCREATE TABLE IF NOT EXISTS— no data is ever lost.
Migrations
Dyrected does not have a built-in migration runner yet. When you add a new field to a collection, the underlying JSON/JSONB column approach means new fields appear automatically in new documents. However, if you need to add a SQL column (e.g., for a native index), handle it with your preferred migration tool:
- PostgreSQL: node-pg-migrate, Flyway, or raw
ALTER TABLEscripts - SQLite: better-sqlite3 with manual
ALTER TABLE - MongoDB: No schema migration required — add fields to your config and they appear in new documents
DatabaseAdapter interface
Implement this interface to support any database. All methods are async.
import type { DatabaseAdapter, PaginatedResult } from '@dyrected/core'
class MyCustomAdapter implements DatabaseAdapter {
// Required: list documents
async find(args: {
collection: string
where?: Record<string, any>
limit?: number
page?: number
sort?: string
}): Promise<PaginatedResult> { ... }
// Required: single document by ID
async findOne(args: { collection: string; id: string }): Promise<any> { ... }
// Required: insert a document
async create(args: { collection: string; data: any }): Promise<any> { ... }
// Required: partial update by ID
async update(args: { collection: string; id: string; data: any }): Promise<any> { ... }
// Required: delete by ID
async delete(args: { collection: string; id: string }): Promise<any> { ... }
// Required: fetch a global singleton
async getGlobal(args: { slug: string }): Promise<any> { ... }
// Required: upsert a global singleton
async updateGlobal(args: { slug: string; data: any }): Promise<any> { ... }
// Optional: create tables/collections on startup
async sync?(collections: CollectionConfig[], globals: GlobalConfig[]): Promise<void> { ... }
// Optional: raw query execution
async execute?(query: string, params?: any[]): Promise<any> { ... }
}PaginatedResult shape
interface PaginatedResult {
docs: any[]
total: number
limit: number
page: number
totalPages: number
hasNextPage: boolean
hasPrevPage: boolean
}