Skip to content

Runtime overview

actor-ts targets three JavaScript runtimes:

RuntimeStatusNotes
BunPrimaryThe runtime we test against first. Native SQLite, native test runner, fastest startup.
Node (≥ 22.12)Fully supportedRequires better-sqlite3 peer dep for SQLite paths.
DenoBest-effortWorks for most features; less testing than Bun/Node.

The framework’s runtime-detection model picks the right backend at startup for runtime-specific things — SQLite drivers, TCP backends, file APIs. You write the same code; the framework adapts.

For most users:

  • Bun if you can. Faster, lighter, fewer peer deps.
  • Node ≥ 22.12 if your environment requires it — most managed platforms (AWS Lambda layers, Cloud Functions, etc.) default to Node.
  • Deno if you’re already invested in it.

The framework checks at module-load time:

if (typeof Bun !== 'undefined') { /* Bun */ }
else if (typeof Deno !== 'undefined') { /* Deno */ }
else if (typeof process !== 'undefined') { /* Node */ }

Specific subsystems (SQLite, TCP, fs) have their own adapter files; each one detects + picks the right backend.

This means no runtime flag — the framework just works on whichever runtime starts it.

For most code, nothing differs:

  • Actor lifecycle.
  • Cluster gossip.
  • Persistence + journals.
  • HTTP routing + serving.
  • Brokers (most don’t care about the runtime).

What does differ:

ConcernBunNodeDeno
SQLitebun:sqlite (built-in)better-sqlite3 (peer dep)Not supported
TCPBun.connect / Bun.listennode:netDeno.connect / Deno.listen
WebSocket serverBun.serve (built-in)ws (peer dep)Deno.serveHttp
HTTP serverFastify / Bun.serve / ExpressFastify / ExpressFastify
File I/OBun.file / node:fsnode:fsDeno.open
Test runnerbun:testnode:test / vitest / jestDeno.test

See the compatibility matrix for the full breakdown.

You can run a cluster with mixed runtimes:

node-1: Bun
node-2: Node 20
node-3: Bun

Cluster gossip + transport are wire-format compatible across all three. Mostly useful for migration — gradual rollout from Node to Bun, for example.

In practice, prefer one runtime per cluster — mixing makes debugging harder (different stack traces, different error messages, different perf profiles).

UpgradeEffort
Bun patch versionsDrop-in; restart pods.
Bun major versionsTest in staging; should be drop-in but worth verifying.
Node patchDrop-in.
Node minor (e.g. 22.x → 22.y)Drop-in.
Node major (e.g. 20 → 22)Test thoroughly; some node APIs change.
Switching Bun ↔ NodeTest full workload; perf profile differs.

For production, pin runtime versions in your container image:

FROM oven/bun:1.1.30 # explicit tag, no `latest`

Bun is recommended for:

  • New projects.
  • Cluster nodes you control.
  • Maximum perf / minimum dependencies.

Node is recommended for:

  • Existing Node-shop infrastructure.
  • Platforms that don’t yet support Bun (AWS Lambda, Cloud Functions, some PaaS).
  • Compliance reasons (Node has a much older audit trail).

Deno is recommended for:

  • Deno-first organizations.
  • Edge-style deployments (Deno Deploy).