Start a live container in one call. Pick any Docker image, set resource limits, and get back a Sandbox you hold like any other object.

Run commands and get stdout, stderr, and exit code back. Stream live output to your process, set a working directory, inject environment variables.

Read and write files directly inside the sandbox. Inject source code, pull build artifacts, inspect logs — all from TypeScript with no extra tooling.

Snapshot the container at any point — filesystem, processes, memory. Resume later from the exact same state. Pay for compute only when you need it.

Branch a running container from any checkpoint. Each fork is an independent Sandbox — run parallel test shards, A/B variants, or speculative executions.

Define a named environment once — image, resources, setup script. drej builds it, snapshots it, and restores from that snapshot on every subsequent call.

Chain steps into a durable workflow. Each step is logged to the ledger — on failure, replay from the last successful checkpoint without re-running earlier work.

Every exec is logged to a durable ledger. Query past sessions, inspect exec counts and timing, or delete records — all through a typed API.

index.ts
const sb = await client.sandbox({
  image: "node:22",
  resources: {
    cpu:    "500m",
    memory: "256Mi",
  },
});
const { stdout } = await sb.exec(
  "node index.js",
);
 
// stream live output
await sb.exec("npm test")
  .pipe(process.stdout);
await sb.writeFile("/app/main.py", src);
 
const logs = await sb.readFile(
  "/var/log/app.log",
);
 
const entries = await sb.listDirectory(
  "/app", { depth: 1 },
);
await sb.checkpoint("before-tests");
 
// restore exact state later
const resumed = await client.resume(
  sandboxId,
);
await resumed.exec("npm test");
await sb.checkpoint();
const fork = await sb.fork();
 
// two independent containers, same state
await Promise.all([
  sb.exec("npm test -- --shard=1/2"),
  fork.exec("npm test -- --shard=2/2"),
]);
const env = client.environment("ci", {
  image: "node:22",
  resources: { cpu: "500m", memory: "512Mi" },
  setup: async (sb) => {
    await sb.exec("npm ci");
  },
});
 
// builds once, restores from snapshot
const sb = await env.sandbox();
await sb.exec("npm test");
await workflow(client)
  .sandbox(
    { image: "node:22", resources },
    async (sb) => {
      await sb.exec("npm ci");
      await sb.exec("npm test");
    },
  )
  .result();
const sessions = await client.sandboxes.list({
  status: SandboxStatus.Running,
  limit: 20,
});
 
const details = await client.sandboxes.get(
  "ci", sandboxId,
);
// { status, execCount, startedAt }