Database Drivers
Configuration reference for supported database drivers
Database Drivers
ObjectStack supports multiple database backends through a unified driver interface. Drivers can be selected in two ways:
-
Env var only — auto-inferred from the URL scheme (the simplest path):
export OS_DATABASE_URL=mongodb://localhost:27017/myapp # → MongoDB export OS_DATABASE_URL=postgres://user:pass@host/db # → PostgreSQL export OS_DATABASE_URL=mysql://user:pass@host/db # → MySQL export OS_DATABASE_URL=file:./data/app.db # → SQLite pnpm devThe CLI inspects the connection-string scheme and picks the right driver automatically. You only need to set
OS_DATABASE_DRIVERwhen you want to override the inference (e.g. forcesqlitefor an ambiguous path). -
Programmatic — register a driver instance as a kernel plugin via
DriverPlugin(the same path the CLI uses internally):import { DriverPlugin } from '@objectstack/runtime'; import { SqlDriver } from '@objectstack/driver-sql'; await kernel.use( new DriverPlugin( new SqlDriver({ client: 'pg', connection: process.env.OS_DATABASE_URL, }), ), );
URL → Driver Inference Table
| URL pattern | Inferred driver | npm package |
|---|---|---|
mongodb://…, mongodb+srv://… | MongoDB | @objectstack/driver-mongodb |
postgres://…, postgresql://… | PostgreSQL (Knex pg) | @objectstack/driver-sql + pg |
mysql://…, mysql2://… | MySQL (Knex mysql2) | @objectstack/driver-sql + mysql2 |
wasm-sqlite://…, *.wasm.db | SQLite (pure-JS WASM) | @objectstack/driver-sqlite-wasm |
file:…, sqlite:…, :memory:, *.db / *.sqlite | SQLite (Knex better-sqlite3) | @objectstack/driver-sql + better-sqlite3 |
| (unset, dev mode) | SQLite (native, falling back to WASM, then in-memory) | @objectstack/driver-sql / -sqlite-wasm / -memory |
Turso / libSQL (libsql://, *.turso.io) is not supported by the
open-source framework — no bundled driver dispatches libsql:// URLs.
Supported Drivers
| Driver | npm package | Class | Explicit OS_DATABASE_DRIVER value |
|---|---|---|---|
| PostgreSQL | @objectstack/driver-sql (peer: pg) | SqlDriver | postgres | postgresql | pg |
| MySQL | @objectstack/driver-sql (peer: mysql2) | SqlDriver | mysql | mysql2 |
| SQLite | @objectstack/driver-sql (peer: better-sqlite3) | SqlDriver | sqlite | sql |
| SQLite (WASM) | @objectstack/driver-sqlite-wasm | SqliteWasmDriver | sqlite-wasm | wasm-sqlite | wasm |
| MongoDB | @objectstack/driver-mongodb | MongoDBDriver | mongodb | mongo |
| Memory | @objectstack/driver-memory | InMemoryDriver | memory |
All SQL flavours (PostgreSQL / MySQL / SQLite) are served by a single
@objectstack/driver-sqlpackage — there is no separatedriver-postgres,driver-mysql, ordriver-sqlitepackage. Pick the Knex client name (pg/mysql2/better-sqlite3) when you instantiateSqlDriver.
PostgreSQL (via @objectstack/driver-sql)
pnpm add @objectstack/driver-sql pgSqlDriver's constructor accepts a Knex Knex.Config object verbatim.
import { SqlDriver } from '@objectstack/driver-sql';
new SqlDriver({
client: 'pg',
connection: {
host: 'db.example.com',
port: 5432,
user: 'admin',
password: process.env.DB_PASSWORD,
database: 'myapp',
ssl: true,
},
pool: { min: 2, max: 10 },
});Or via env var alone (driver inferred from postgres:// scheme):
export OS_DATABASE_URL=postgres://admin:secret@db.example.com:5432/myappMongoDB
Configuration properties for the MongoDB driver.
| Property | Type | Required | Description |
|---|---|---|---|
| url | string | ✅ | Connection URI (e.g., mongodb://host:27017/db) |
| database | string | optional | Database name (overrides the database in the URI) |
| maxPoolSize | number | optional | Max connection pool size (default: 10) |
| minPoolSize | number | optional | Min connection pool size (default: 1) |
| connectTimeoutMS | number | optional | Connection timeout in milliseconds |
| serverSelectionTimeoutMS | number | optional | Server selection timeout in milliseconds |
| options | MongoClientOptions | optional | Additional MongoClient options (e.g. ssl, replicaSet, readPreference, authSource) |
Example (config):
import { MongoDBDriver } from '@objectstack/driver-mongodb';
new MongoDBDriver({
url: 'mongodb+srv://admin:secret@cluster.mongodb.net/myapp',
maxPoolSize: 50,
options: { readPreference: 'nearest' },
});Example (env-var, recommended for objectstack dev / objectstack serve):
export OS_DATABASE_URL=mongodb://localhost:27017/myapp
pnpm devThe CLI infers the MongoDB driver from the mongodb:// (or mongodb+srv://)
URL scheme automatically — no OS_DATABASE_DRIVER needed. Set
OS_DATABASE_DRIVER=mongodb only if you want to be explicit.
SQLite (via @objectstack/driver-sql)
SQLite is ideal for local-first development and embedded applications.
It uses the same SqlDriver class with client: 'better-sqlite3'.
pnpm add @objectstack/driver-sql better-sqlite3import { SqlDriver } from '@objectstack/driver-sql';
new SqlDriver({
client: 'better-sqlite3',
connection: { filename: './data/app.db' },
useNullAsDefault: true,
});Env-var path (driver inferred from file: / :memory: / .db paths):
export OS_DATABASE_URL=file:./data/app.db
# or
export OS_DATABASE_URL=:memory:Space Reclamation & Table Rotation (ADR-0057)
The SQL driver connects SQLite with auto_vacuum=INCREMENTAL and exposes
reclaimSpace() (PRAGMA incremental_vacuum), which the platform
LifecycleService calls after every sweep that deleted rows — so the database
file actually shrinks instead of pinning at its high-water mark. Objects
declaring lifecycle.storage.strategy: 'rotation' are physically
time-sharded on SQLite: writes land in the current shard, reads go through a
view under the table's name, and expired shards are reclaimed with a single
DROP TABLE. On PostgreSQL/MySQL both are no-ops — those engines manage
space with their own vacuum machinery, and rotation falls back to an
equivalent age-based reap.
Memory Driver
The in-memory driver keeps records in plain in-process objects (queried via
mingo). Data is lost when the process exits.
It is the last-resort fallback in dev mode: objectstack dev prefers native
SQLite (better-sqlite3), falls back to the pure-JS WASM SQLite driver if the
native binary is unavailable, and only drops to the in-memory driver if WASM also
fails to load. Set OS_DATABASE_DRIVER=memory to select it explicitly.
import { InMemoryDriver } from '@objectstack/driver-memory';
new InMemoryDriver();Use the memory driver for unit tests. It requires no setup and runs instantly.
Local Environment Runtime
Local framework commands run one active environment. The business records served
at /api/v1/data/* use the driver selected by OS_DATABASE_URL and
OS_DATABASE_DRIVER.
# Run the showcase with MongoDB as the local environment DB:
OS_ENVIRONMENT_ID=env_local \
OS_DATABASE_URL=mongodb://localhost:27017/objectstack \
pnpm dev
# Pin the driver explicitly when the URL is ambiguous:
OS_DATABASE_URL=file:./.objectstack/data/app.db \
OS_DATABASE_DRIVER=sqlite \
pnpm devCloud control-plane databases and environment provisioning live in the Cloud
distribution outside this framework repo. When this runtime is pointed at Cloud,
the environment id still flows through OS_ENVIRONMENT_ID, scoped URLs, or
X-Environment-Id; mutable deployment config does not live in the compiled
artifact.
Multi-Datasource
ObjectStack supports multiple data sources. Objects can target specific datasources:
Datasources are declared as metadata descriptors ({ driver, config }) — the
map key becomes the datasource name:
import { defineStack } from '@objectstack/spec';
export default defineStack({
datasources: {
analytics: {
driver: 'postgres',
config: { url: process.env.ANALYTICS_URL },
},
cache: {
driver: 'mongodb',
config: { url: process.env.MONGO_URL },
},
},
});Then in your object definition:
export const AuditLog = ObjectSchema.create({
name: 'audit_log',
datasource: 'analytics', // Routes to the analytics database
fields: { /* ... */ },
});