Skip to content

Multi-Runtime Support

Conveyor runs on Deno 2, Node.js 18+, and Bun as first-class targets. The core package achieves this by using only Web Standards APIs, while runtime-specific concerns are isolated in store packages.

Design Principle: Web Standards Only in Core

The @conveyor/core and @conveyor/shared packages never use runtime-specific APIs. They rely exclusively on APIs available across all modern JavaScript runtimes:

API UsedPurposeStandard
setTimeoutPolling loops, delayed timersWHATWG Timers
clearTimeoutCancelling timersWHATWG Timers
EventTargetLocal event busDOM Events
crypto.randomUUID()Generating job and worker IDsWeb Crypto API
structuredClone()Defensive copies of job dataHTML Structured Clone
DateTimestampsECMAScript
AbortControllerCancellation signals for workersDOM Abort
PromiseAsync operationsECMAScript

This means @conveyor/core works identically on Deno, Node.js, and Bun without any polyfills or conditional imports.

Runtime-Specific Packages

Only the store layer contains runtime-specific code. The SQLite stores are split into separate packages because each runtime provides a different SQLite driver:

PackageRuntimeSQLite DriverNotes
@conveyor/store-sqlite-nodeNode.jsnode:sqlite (DatabaseSync)Built-in since Node 22.13+
@conveyor/store-sqlite-bunBunbun:sqliteBuilt-in
@conveyor/store-sqlite-denoDenoDeno SQLite bindingsBuilt-in since Deno 2.2+

All three SQLite packages extend a shared base (@conveyor/store-sqlite-core) that contains the SQL queries, migration logic, and state management. Only the thin driver adapter differs per runtime.

The PostgreSQL and memory stores are runtime-agnostic:

PackageWorks OnDriver
@conveyor/store-pgAll runtimespostgres (npm)
@conveyor/store-memoryAll runtimesNone (in-process)

Import Patterns

Deno

Conveyor is published on JSR. Use jsr: specifiers or import maps:

ts
import { Queue, Worker } from 'jsr:@conveyor/core';
import { MemoryStore } from 'jsr:@conveyor/store-memory';
import { PgStore } from 'jsr:@conveyor/store-pg';
import { SqliteDenoStore } from 'jsr:@conveyor/store-sqlite-deno';

Or with an import map in deno.json:

jsonc
{
  "imports": {
    "@conveyor/core": "jsr:@conveyor/core@^0.4.0",
    "@conveyor/store-memory": "jsr:@conveyor/store-memory@^0.4.0",
    "@conveyor/store-pg": "jsr:@conveyor/store-pg@^0.4.0",
    "@conveyor/store-sqlite-deno": "jsr:@conveyor/store-sqlite-deno@^0.4.0"
  }
}

Node.js

Install from JSR using your preferred package manager:

bash
npx jsr add @conveyor/core @conveyor/store-memory

Then import normally:

ts
import { Queue, Worker } from '@conveyor/core';
import { MemoryStore } from '@conveyor/store-memory';
import { SqliteNodeStore } from '@conveyor/store-sqlite-node';

Bun

Bun supports JSR packages the same way:

bash
bunx jsr add @conveyor/core @conveyor/store-memory
ts
import { Queue, Worker } from '@conveyor/core';
import { MemoryStore } from '@conveyor/store-memory';
import { SqliteBunStore } from '@conveyor/store-sqlite-bun';

Choosing the Right Store for Your Runtime

RuntimeRecommended StoreWhy
Denostore-sqlite-deno or store-pgDeno has built-in SQLite; PG for multi-node
Node.jsstore-sqlite-node or store-pgnode:sqlite is built-in since 22.13+
Bunstore-sqlite-bun or store-pgbun:sqlite is built-in and fast
Anystore-memoryTests and prototyping (all runtimes)

Runtime Compatibility Matrix

FeatureDeno 2+Node.js 18+Bun 1.2+
@conveyor/coreYesYesYes
@conveyor/sharedYesYesYes
@conveyor/store-memoryYesYesYes
@conveyor/store-pgYesYesYes
@conveyor/store-sqlite-denoYes----
@conveyor/store-sqlite-node--Yes--
@conveyor/store-sqlite-bun----Yes

Testing Across Runtimes

The project uses Vitest for all runtimes except Bun (which uses bun test). Conformance tests in tests/conformance/ run the same test suite against every store implementation to guarantee identical behavior.

bash
# Run all tests (Deno)
deno task test

# Run tests for specific stores
deno task test:core          # Core + conformance
deno task test:memory        # Memory store
deno task test:pg            # PostgreSQL (needs Docker)
deno task test:sqlite:node   # SQLite on Node.js
deno task test:sqlite:bun    # SQLite on Bun
deno task test:sqlite:deno   # SQLite on Deno

Writing Runtime-Agnostic Code

When building applications with Conveyor, keep your job processing logic runtime-agnostic by following the same principle the library itself uses:

ts
// config.ts -- the only file that changes per environment
import { PgStore } from '@conveyor/store-pg';

export const store = new PgStore({
  connectionString: process.env.DATABASE_URL!,
});

// worker.ts -- pure business logic, no runtime-specific code
import { Queue, Worker } from '@conveyor/core';
import { store } from './config.ts';

await store.connect();

const queue = new Queue('emails', { store });
const worker = new Worker('emails', async (job) => {
  // This code runs identically on Deno, Node.js, and Bun
  await sendEmail(job.data.to, job.data.subject);
}, { store });

By isolating the store selection to a single configuration file, you can switch runtimes or backends without touching any business logic.

Released under the MIT License.