@beamcloud/beam-js
v1.1.6
Published
TypeScript and JavaScript SDK for Beam
Readme
Beam TypeScript/JavaScript SDK
The official TypeScript and JavaScript SDK for Beam.
Install
npm install @beamcloud/beam-jsyarn add @beamcloud/beam-jsConfigure
Set your Beam token and workspace ID before making SDK calls.
import { beamOpts } from "@beamcloud/beam-js";
beamOpts.token = process.env.BEAM_TOKEN!;
beamOpts.workspaceId = process.env.BEAM_WORKSPACE_ID!;The SDK targets Beam Cloud by default.
Virtual machines
Create a durable Linux VM, run commands, snapshot its root, and fork it:
import { beamOpts, VM } from "@beamcloud/beam-js";
beamOpts.token = process.env.BEAM_TOKEN!;
const vm = await VM.create({
name: "agent-workspace",
cpu: 1,
memory: "2Gi",
protectedPorts: [7681],
idleTimeout: 300,
idleAction: "pause",
autoResume: true,
});
console.log(vm.publicIpv6); // Persistent IPv6 address, when public networking is enabled.
const command = await vm.exec(["node", "--version"]);
await command.wait();
console.log(await command.stdout.read());
const snapshot = await vm.snapshots.create("ready");
const branch = await snapshot.fork({ name: "experiment", memory: "512Mi" });
await branch.remove();
await snapshot.delete();
await vm.pause();
await vm.close();
// Later: await VM.connect(vm.id); to delete: await vm.remove().VMs default to digest-pinned Ubuntu 24.04, 4 CPUs, 8 GiB RAM and a 50 GiB
writable root. Desktop is opt-in (desktop: true, minimum 1 GiB RAM); Docker
requires dockerEnabled: true. Creation waits for guest commands. Use
await vm.wait({ services: true }) for SSH, terminal and enabled desktop;
Docker helpers wait for the daemon separately.
One VM object exposes lifecycle, snapshots/templates, files, Docker, desktop
controls, private tunnels, SSH/SCP, directory sync, prompts, logs and metrics.
See the VM guide and complete API/parity map.
For a runnable JavaScript workflow with cleanup, see
the agent workspace example.
Sandbox Quickstart
Create a sandbox, run code, stream logs, and terminate it cleanly.
import { beamOpts, Image, Sandbox } from "@beamcloud/beam-js";
beamOpts.token = process.env.BEAM_TOKEN!;
beamOpts.workspaceId = process.env.BEAM_WORKSPACE_ID!;
async function main() {
const sandbox = new Sandbox({
name: "examples",
image: new Image({ pythonPackages: ["requests"] }),
cpu: 1,
memory: 1024,
keepWarmSeconds: 300,
});
const sb = await sandbox.create();
const result = await sb.runCode(`
import requests
print(requests.get("https://api.github.com").status_code)
`);
console.log(result);
const process = await sb.exec(["python3", "-c", "print('hello from Beam')"]);
for await (const line of process.logs) {
console.log(line.trimEnd());
}
await sb.terminate();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});name is the Beam app name used to group sandboxes. Each running sandbox still gets its own generated sandbox ID.
Expose a Port
const server = await sb.execShell("python3 -m http.server 8888 --bind 0.0.0.0");
const url = await sb.exposePort(8888);
console.log(url);
await server.kill();Filesystem
await sb.fs.writeText("/tmp/hello.txt", "hello");
console.log(await sb.fs.readText("/tmp/hello.txt"));
await sb.fs.mkdir("/tmp/data");
await sb.fs.uploadFile("./local.txt", "/tmp/data/local.txt");
console.log(await sb.fs.list("/tmp/data"));
await sb.fs.remove("/tmp/data/local.txt");Snapshots
const checkpointId = await sb.snapshot();
await sb.terminate();
const restored = await Sandbox.createFromSnapshot(checkpointId);
console.log(restored.sandboxId);Docker
Install Docker in the image and enable the managed daemon explicitly:
const sandbox = new Sandbox({
name: "docker-actions",
image: Image.fromRegistry("node:20-slim").withDocker(),
dockerEnabled: true,
cpu: 2,
memory: "2Gi",
keepWarmSeconds: 300,
});
const sb = await sandbox.create();
try {
const ready = await sb.exec([
"timeout", "60", "sh", "-c",
"until docker info >/dev/null 2>&1; do sleep 1; done",
]);
if (await ready.wait() !== 0) throw new Error("Docker daemon did not become ready");
const proc = await sb.exec([
"docker", "run", "--rm", "--network=host", "--pid=host",
"alpine:3.20", "echo", "hello",
], { wait: true });
if (await proc.wait() !== 0) throw new Error(await proc.stderr.read());
console.log(await proc.stdout.read());
} finally {
await sb.terminate();
}withDocker() supports Ubuntu and Debian images and installs Docker Engine,
CLI, Buildx, docker compose, and the docker-compose alias. Other base images
must provide their own Docker installation. No host Docker socket is mounted.
Run Docker commands through sb.exec or sb.execShell; a separate Python-style
sb.docker wrapper is not required. The daemon starts asynchronously: wait for
docker info to succeed before issuing builds or running containers.
The managed daemon uses VFS storage and no default bridge under runc/gVisor.
Use --network=host --pid=host for inner containers; these share the sandbox's
namespaces, not the worker machine's. For Compose, configure each service with
network_mode: host and pid: host. Use docker compose -f /path/compose.yaml up
and down through exec; Compose files are not automatically rewritten.
Build with docker build --network=host -t my-image /path/to/context; otherwise
Dockerfile RUN instructions fail with network bridge not found, even when
the instruction does not access the network.
Volumes and Cloud Buckets
import { CloudBucket, Volume } from "@beamcloud/beam-js";
const volume = new Volume("cache", "/mnt/cache");
const bucket = new CloudBucket("my-bucket", "/mnt/bucket", {
accessKey: "AWS_ACCESS_KEY_ID",
secretKey: "AWS_SECRET_ACCESS_KEY",
region: "us-east-1",
});
const sandbox = new Sandbox({
name: "storage",
volumes: [volume, bucket],
});Development
To point the SDK at a local gateway:
beamOpts.gatewayUrl = "http://localhost:1993";