Adapters
Native vs fetch adapters
Section titled “Native vs fetch adapters”jsorm keeps database access outside the ORM core. You choose the adapter based on where your code runs:
- Native adapters (
@jsorm/pg,@jsorm/mysql,@jsorm/sqlite) for Node/Bun runtimes with direct database access. - Fetch adapter (
@jsorm/fetch) for edge or fetch-only runtimes that cannot open TCP sockets or spawn native binaries.
Use @jsorm/node for the CLI and production deploy/migration workflows, even when your app runtime uses @jsorm/runtime + @jsorm/fetch.
Adapter packages
Section titled “Adapter packages”| Package | Kind | Best for |
|---|---|---|
@jsorm/pg | Native TCP adapter | PostgreSQL in Node services, workers, CI, and deploy jobs |
@jsorm/mysql | Native TCP adapter | MySQL-compatible targets such as PlanetScale from Node |
@jsorm/sqlite | Native in-process adapter | Local SQLite files, embedded apps, tests, and tooling |
@jsorm/fetch | HTTP/fetch adapter | Vercel Edge, Cloudflare Workers, and other fetch-only runtimes |
Runtime compatibility matrix
Section titled “Runtime compatibility matrix”| Runtime / workflow | Native adapters | @jsorm/fetch | Recommended choice |
|---|---|---|---|
| Node.js app server | Yes | Yes | Prefer native adapters |
| Bun service/runtime | Yes | Yes | Prefer native adapters when direct DB access exists |
| Deno runtime | SQLite only | Yes | Prefer fetch unless you explicitly run SQLite |
| Vercel Edge / Cloudflare Workers / Netlify Edge | No | Yes | Use @jsorm/runtime + @jsorm/fetch |
CLI, migrations, jsorm deploy | Yes | No | Use @jsorm/node + native adapter |
Choose the right adapter
Section titled “Choose the right adapter”Use native adapters when
Section titled “Use native adapters when”- your runtime can open direct PostgreSQL/MySQL connections
- you run long-lived Node or Bun services
- you want the default production path for
jsorm deploy - your deploy or CI job owns migrations
Use @jsorm/fetch when
Section titled “Use @jsorm/fetch when”- your runtime is edge-only or fetch-only
- you cannot open TCP sockets from request handlers
- you can expose an HTTP SQL gateway that jsorm can call
- you keep migrations and deploy checks in a separate Node release step
Native adapter example
Section titled “Native adapter example”import { createJsorm, defineConnectionSource, defineJsormConfig } from '@jsorm/core';import { pgAdapter } from '@jsorm/pg';
const main = defineConnectionSource({ adapter: pgAdapter({ name: 'main', connectionString: process.env.DATABASE_URL!, pool: { min: 2, max: 10 }, }),});
export default defineJsormConfig({ connectionSources: { main }, defaults: { connectionSource: 'main' },});
export const db = await createJsorm().init();import { createJsorm, defineConnectionSource, defineJsormConfig } from '@jsorm/core';import { mysqlAdapter } from '@jsorm/mysql';
const main = defineConnectionSource({ adapter: mysqlAdapter({ name: 'main', uri: process.env.DATABASE_URL!, pool: { min: 1, max: 5 }, }),});
export default defineJsormConfig({ connectionSources: { main }, defaults: { connectionSource: 'main' },});
export const db = await createJsorm().init();import { createJsorm, defineConnectionSource, defineJsormConfig } from '@jsorm/core';import { sqliteAdapter } from '@jsorm/sqlite';
const main = defineConnectionSource({ adapter: sqliteAdapter({ name: 'main', file: process.env.DB_PATH ?? './data/app.db', }),});
export default defineJsormConfig({ connectionSources: { main }, defaults: { connectionSource: 'main' },});
export const db = await createJsorm().init();Fetch adapter example
Section titled “Fetch adapter example”Use runtime-safe imports in edge bundles:
import { createJsorm, defineConnectionSource, defineJsormConfig } from '@jsorm/runtime';import { fetchAdapter } from '@jsorm/fetch';
const main = defineConnectionSource({ adapter: fetchAdapter({ name: 'main', dialect: 'postgres', endpoint: process.env.SQL_HTTP_ENDPOINT!, headers: () => ({ authorization: `Bearer ${process.env.SQL_HTTP_TOKEN!}`, }), }),});
export default defineJsormConfig({ connectionSources: { main }, defaults: { connectionSource: 'main' },});
export const db = await createJsorm().init();Production guidance
Section titled “Production guidance”| Environment | App runtime | Adapter | Production note |
|---|---|---|---|
| Node API / worker / queue | @jsorm/core or @jsorm/node | Native | Best default for direct DB access and release jobs |
| Vercel Edge | @jsorm/runtime | @jsorm/fetch | Keep jsorm deploy in GitHub Actions or another Node step |
| Cloudflare Workers | @jsorm/runtime | @jsorm/fetch | Point the adapter at an HTTP SQL endpoint you control |
| Docker / CI deploy job | @jsorm/node | Native | Run pnpm exec jsorm deploy --strict --verbose before rollout |
Health checks
Section titled “Health checks”Use adapter-level health checks in runtime code:
const health = await db.healthCheck();// { main: 'ok', analytics: 'ok' }And in Node deploy or readiness workflows:
pnpm exec jsorm db:check- Native adapters are the default choice for deploy preflight checks.
- Fetch adapters can still participate in
db.healthCheck(), but your HTTP endpoint must be reachable, authenticated, and healthy.
Transactions
Section titled “Transactions”Transactions are scoped to a single connection source:
await db.transaction(async (tx) => { await tx.insert(User, { name: 'Alice', createdAt: new Date(), });});- Native adapters support single-database transactions directly.
@jsorm/fetchalso supports transactions, but your HTTP SQL endpoint must implementbegin,commit, androllback.- Cross-database transactions are not supported.
Multi-database and scoped clients
Section titled “Multi-database and scoped clients”jsorm allows registering multiple connectionSources for read/write splits or different databases. Use db.use(name) to get a lightweight scoped client, or db.with(name, fn) to scope operations within a block.
import { createJsorm, defineConnectionSource, defineJsormConfig } from '@jsorm/core';import { pgAdapter } from '@jsorm/pg';
const main = defineConnectionSource({ /* ... */ });const analytics = defineConnectionSource({ /* ... */ });
export default defineJsormConfig({ connectionSources: { main, analytics }, defaults: { connectionSource: 'main' },});
export const db = await createJsorm().init();
// Uses 'main' connection by defaultawait db.get(User, { select: { id: true } });
// Scoped client for 'analytics' connectionconst analyticsDb = db.use("analytics");await analyticsDb.get(User, { select: { id: true } });
// Scoped blockawait db.with("analytics", async (scoped) => { await scoped.raw.execute("SELECT 1");});Best fit by environment
Section titled “Best fit by environment”- Default production Node app: native adapter.
- Edge request path:
@jsorm/runtime+@jsorm/fetch. - Migrations and deploy:
@jsorm/node+ native adapter. - Local embedded SQLite:
@jsorm/sqlite.