One API, any provider
Use common create, exec, files and destroy calls. Choose provider configuration and check its supported capabilities.
A typed API to create, run code in, and tear down sandboxes on Daytona, E2B, boxd, Boat, Runloop and Vercel. Keep application workflows consistent while configuring each provider explicitly.
import { Beachside, Image } from "beachside"
import { daytona } from "@beachside/daytona"
const client = await Beachside.connect(
daytona({
apiKey: process.env.DAYTONA_API_KEY!,
target: "us",
environment: Image.prepared("daytona-small"),
networkPolicy: "daytona-default",
}),
)import { Beachside } from "beachside"
import { boxdAdapter } from "@beachside/boxd"
const client = await Beachside.connect({
adapter: boxdAdapter,
credentials: { apiKey: process.env.BOXD_API_KEY! },
config: { org: process.env.BOXD_ORG!, networkPolicy: "internet" },
})import { Beachside } from "beachside"
import { vercel } from "@beachside/vercel"
const client = await Beachside.connect({
adapter: vercel,
credentials: { token: process.env.VERCEL_TOKEN! },
config: {
teamId: process.env.BEACHSIDE_VERCEL_TEAM_ID!,
projectId: process.env.BEACHSIDE_VERCEL_PROJECT_ID!,
},
})
await client.sandboxes.with({}, async (box) => {
const run = await box.exec(["printf", "ready"])
console.log(run.stdoutText())
})
await client.close()beachside creates, runs in and removes sandboxes on any provider with an adapter. It never prompts, every command has a --json form, and exit codes say what to do next, so your coding agent can drive it as easily as you can.
$ export BEACHSIDE_PROVIDER=e2b E2B_API_KEY=...
$ beachside create --name web
web
$ beachside cp ./app.py web:/tmp/app.py
$ beachside exec web -- python3 /tmp/app.py
hello from e2b
$ beachside ls
NAME STATE PROVIDER PROFILE ID CREATED
web running e2b e2b i8mq2v0x7cz4 2026-10-19T09:41:07.312Z
$ beachside rm web
web
Use common create, exec, files and destroy calls. Choose provider configuration and check its supported capabilities.
Save references to recover across invocations. Scope sandbox cleanup while keeping snapshots and volumes.
OpenTelemetry traces connect SDK calls, provider operations, errors, and recovery context. Integrates with Sentry and Datadog.
Implement create and destroy to start. Add exec, files and recovery as your provider supports them.
Wrap any sandbox API with defineAdapter. Declare config and credential schemas, implement the operations your provider supports, and Beachside handles lifecycle, error mapping and recovery around it.
// Inside your adapter's connect() method:
// Authenticate the client and verify scope first.
return {
scope,
supports: { images: ["prepared"], network: ["blocked"] },
async create(input, ctx) {
const box = await client.spawn({
account: account.id,
imageId: input.image.value,
region: config.region,
blockAllEgress: true,
public: false,
requestId: ctx.submissionId,
});
return {
id: box.id,
state: box.ready ? "running" : "unknown",
};
},
async destroy(box) {
await client.deleteAndWait(box.id, account.id, config.region);
return { computeStopped: true, retainedResources: [] };
},
};