Skip to content

Runtimes

jsorm separates authoring APIs, runtime-safe imports, CLI ownership, and database transport so each environment gets only what it can safely run.

| Package | Use it for | Do not use it for | | --- | --- | --- | | @jsorm/core | Main authoring package for models, queries, config types, and migration primitives in Node-capable apps | Edge bundles that cannot use Node APIs or native binaries | | @jsorm/runtime | Universal or edge-safe application code, plus direct config injection when filesystem access is unavailable | Owning the jsorm CLI | | @jsorm/node | Tooling and runtime package for Node and Bun. On Node it provides the Rust engine bridge and native adapter plumbing for migrations and deploy workflows. On Bun it detects Bun config and uses Bun native DB APIs directly (no Rust engine) | CLI ownership or edge request handlers | | @jsorm/fetch | HTTP/fetch database transport for runtimes without TCP sockets or native binaries | Migration ownership or jsorm deploy | | @jsorm/pg, @jsorm/mysql, @jsorm/sqlite | Native adapters for direct database access from Node | Edge runtimes without raw TCP access |

  • Node app runtime: @jsorm/core or @jsorm/node with a native adapter package
  • Bun runtime: @jsorm/node — detects Bun and uses Bun native database APIs directly, no Rust engine
  • Edge runtime: @jsorm/runtime with @jsorm/fetch
  • CI, release, and deploy jobs: @jsorm/core + @jsorm/node in a Node 24+ environment

Use native adapters when your runtime can open direct database connections and run Node APIs.

Terminal window
pnpm add @jsorm/core @jsorm/node @jsorm/pg pg
import { createJsorm, defineConnectionSource, defineJsormConfig } from '@jsorm/core';
import { pgAdapter } from '@jsorm/pg';
const main = defineConnectionSource({
adapter: pgAdapter({
name: 'main',
connectionString: process.env.DATABASE_URL!,
}),
});
const config = defineJsormConfig({
connectionSources: { main },
defaults: { connectionSource: 'main' },
});
export const db = await createJsorm().init(config);

Use this shape for long-lived servers, background workers, and containerized Node apps.

Use @jsorm/node on Bun. The package detects the Bun runtime and uses Bun’s built-in SQLite, MySQL-compatible, and PostgreSQL-compatible APIs directly — bypassing the Rust engine entirely.

Terminal window
pnpm add @jsorm/core @jsorm/node @jsorm/pg pg
import { createJsorm, defineConnectionSource, defineJsormConfig } from '@jsorm/core';
import { pgAdapter } from '@jsorm/pg';
const main = defineConnectionSource({
adapter: pgAdapter({
name: 'main',
connectionString: process.env.DATABASE_URL!,
}),
});
const config = defineJsormConfig({
connectionSources: { main },
defaults: { connectionSource: 'main' },
});
export const db = await createJsorm().init(config);

On Bun, adapter calls go through Bun’s native database bindings instead of the Rust worker. The query API, type inference, and config shape are identical to Node.

Use runtime-safe imports plus @jsorm/fetch when the request runtime cannot use raw TCP sockets or native binaries.

Terminal window
pnpm add @jsorm/runtime @jsorm/fetch
pnpm add -D @jsorm/node
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!}`,
}),
}),
});
const config = defineJsormConfig({
connectionSources: { main },
defaults: { connectionSource: 'main' },
});
export const db = await createJsorm().init(config);

This is the recommended path for Vercel Edge, Cloudflare Workers, and other fetch-only runtimes.

Run migration and deploy commands from Node, even if the application itself runs at the edge.

Terminal window
pnpm exec jsorm deploy --strict --verbose

Typical places to run this:

  • GitHub Actions
  • a release container or init job
  • a dedicated Node deployment step before rollout

| Environment | Runtime package | Transport | Migration/deploy owner | | --- | --- | --- | --- | | Node API/server | @jsorm/core or @jsorm/node | native adapter | same Node runtime or CI job | | Bun service / script | @jsorm/node | Bun native API | same Bun runtime or CI job (Node) | | Vercel Edge / Workers | @jsorm/runtime | @jsorm/fetch | separate @jsorm/core + @jsorm/node job | | CI / release pipeline | @jsorm/core + @jsorm/node | native adapter | @jsorm/core + @jsorm/node |

jsorm uses a persistent worker process by default in Node runtimes to eliminate per-query spawn overhead. When engine.mode is omitted in jsorm.config.ts, it defaults to "worker".

// jsorm.config.ts
export default defineJsormConfig({
engine: {
// mode defaults to "worker"
worker: {
startupTimeoutMs: 5_000,
requestTimeoutMs: 10_000,
restartLimit: 3,
},
},
});

You can fall back to legacy per-query execution by explicitly setting engine.mode: "spawn" if needed. Note that worker mode is Node.js runtime only — on Bun, @jsorm/node bypasses the Rust engine entirely and uses Bun’s native database APIs.

Runtimes in the same Node process share adapter pools and Rust worker processes when their effective configuration fingerprint matches.

  • createJsorm(): Standard instances automatically participate in the shared-resource registry. This avoids recreating DB connection pools across repeated imports.
  • createJsormTest(): Sandboxed instances for testing intentionally disable filesystem config discovery and isolate their resources by default, preventing tests from trampling on each other’s pools.
import { createJsorm, createJsormTest } from '@jsorm/core';
// Reuses shared worker and connection pools based on config fingerprint
const appDb = await createJsorm().init();
// Uses isolated resources by default
const testDb = await createJsormTest().init();

Choose the adapter package that matches your database:

  • PostgreSQL → @jsorm/pg
  • MySQL / PlanetScale → @jsorm/mysql
  • SQLite → @jsorm/sqlite

Install only the adapter packages you actually use. The core packages do not bundle database drivers by default.

  1. Keep app/runtime imports and CLI ownership separated.
  2. Use native adapters in Node, and @jsorm/fetch only for fetch-only runtimes.
  3. On Bun, @jsorm/node detects the runtime automatically — the same package works for both Node and Bun.
  4. Run jsorm deploy outside edge functions.
  5. Treat CI and release jobs as Node environments with full migration responsibility.