Skip to content

Images and networking

Set the default environment and network policy in adapter setup. Your application can then use beachside.sandboxes.create() without repeating those choices. See Getting started for connection examples.

Image.prepared(value) selects an existing provider image. It does not build an image or capture a running sandbox.

Provider Prepared image Connection setup
E2B base, or a ready owned template ID/name templateId defaults to base. Set it to use your own template.
Daytona Active Linux snapshot ID/name Set environment: Image.prepared("your-snapshot"). It must be available in your organization and region.
Vercel Sandbox vercel/sandbox/universal:latest Default. Set image to a managed Node 22, 24 or 26 image instead; other images are unsupported.

Daytona calls its prepared images snapshots. Selecting one as an image is different from capturing a sandbox’s current state. For capture and restore, use the snapshot APIs.

boxd starts directly from an OCI image instead of a prepared image. Set image in its adapter configuration, or omit it to use the authenticated cluster’s default image. Starting from OCI does not create a separate Beachside image-build artifact. See boxd defaults.

An explicit environment on create() overrides the connection default if the adapter supports it. An invalid override fails; Beachside does not silently fall back to another image. Vercel accepts only its configured managed image.

E2B and Daytona implement images.build() to turn an OCI image into a reusable prepared image. Builds are separate provider operations and may incur build and storage charges. boxd boots OCI images directly and does not implement this build API; Vercel supports neither custom OCI images nor builds. (await client.capabilities()).imageBuild is true on connections that implement the build. Check tested provider support for live coverage.

Start with an E2B or Daytona connection named beachside:

import { Image } from "beachside";
const built = await beachside.images.build({ source: Image.oci("node:24") });
console.log(built.retainedResources);
const box = await beachside.sandboxes.create({
environment: Image.prepared(built.prepared),
});
try {
console.log((await box.exec(["node", "--version"])).stdoutText());
} finally {
await box.destroy();
}

Creation uses the connection’s network policy. Close the connection in an outer finally after handling resources, as in Getting started. images.submitBuild() returns an operation handle if you need to save an operation reference and recover its result later.

Pass the full built.prepared value to Image.prepared(): it includes the provider and verified scope, so another account or scope cannot accidentally use it. Public OCI references are supported; the SDK has no shared private-registry credential option. Daytona requires a version tag or SHA-256 digest and rejects latest, lts and stable. Use a digest when you need an exact immutable image.

Destroying a sandbox does not delete its built template or snapshot. Keep built.reference (or built.retainedResources) available and delete images you own separately, including when sandbox creation fails. Borrowed prepared images are never sandbox cleanup targets.

built.reference is a resource reference of kind "image". Its ownership is "verified-created" only when the adapter proved this build created the image; a build recovered after a lost response reports "unknown". Persist the whole reference, then reopen and delete the image with it:

const image = await beachside.images.get(built.reference);
console.log(await image.inspect()); // state, visibility, source and known dependencies
await image.delete(); // or beachside.images.delete(built.reference)

images.list({ limit: 20, cursor }) returns a bounded page of the provider’s images with a coverage value, like snapshot and volume inventory. Finding an image in a list does not prove you own it, so listed items have unknown ownership. (await beachside.capabilities()).imageManagement reports whether inspect, list and delete are supported; a missing operation rejects with UNSUPPORTED.

Deletion follows the snapshot deletion rules. The reference must match the connection’s provider and scope. The adapter refuses public or shared images, captured sandbox snapshots (delete those with snapshots.delete()) and images that sandboxes or other native resources still use, rejecting with no effect before it sends anything. Deletion sends one native request and never resends it. If the response is lost and the image is not then observed gone, delete() rejects with OUTCOME_UNKNOWN; submitDelete() returns an operation whose saved reference you can recover later to learn whether the image is gone.

Provider Images Get, list and delete
E2B Templates Supported. Delete only removes a private, single-build template that no sandbox uses. See E2B.
Daytona Native snapshots Supported. Delete refuses general snapshots and snapshots used by warm pools. See Daytona.
boxd OCI images, booted directly Unsupported: there is no provider-side image resource.
Vercel Sandbox Managed images only Unsupported.

Image deletion has deterministic test coverage only; no live deletion has been recorded.

Configure network once in adapter setup. Every adapter uses the same names, so switching providers does not change application code:

Provider network Meaning
E2B blocked (default) Requests E2B’s disabled-internet setting; measured strict outbound isolation has not passed.
E2B internet Requests internet access.
Daytona blocked Requests strict block-all. Creation requires verified organization eligibility, with no automatic fallback.
Daytona internet Unrestricted egress. Creation requires an organization without limited sandbox egress (Tier 3 and above).
Daytona daytona-default (default) Daytona-only setup value: keeps organization-managed restrictions, including essential-service access.
boxd internet (required) Allows internet access with native peer/metadata isolation. Strict blocked egress is unsupported.
Vercel Sandbox blocked (default) Requests native deny-all; network isolation has no recorded live acceptance.
Vercel Sandbox internet Requests native allow-all.
// Only the adapter setup differs between providers.
const client = await Beachside.connect(e2b({ apiKey, network: "internet" }));
const box = await client.sandboxes.create();

A requested policy is not proof of isolation. E2B’s maintained test still connected by direct IPv4 TCP when blocked was requested, even though hostname resolution failed. Prepared-image baseline tests do not test outbound isolation. See provider support before relying on a policy to isolate untrusted code.

Daytona’s internet never falls back to daytona-default: on a Tier 1 or Tier 2 organization it rejects before allocation, because Daytona’s default firewall there only reaches essential services. Choose daytona-default in setup when that restricted egress is acceptable. boxd’s peer/metadata isolation does not block outbound internet.

Omitted create and restore policies use the connection default, so most applications never pass network per call. An explicit create({ network }) or restore({ network }) must be supported by that connection: E2B accepts blocked or internet, while Daytona and Vercel require a match with the configured policy. boxd accepts only internet. Empty or null policies reject rather than selecting a fallback. client.capabilities().network lists what the connection accepts.

The option was previously named networkPolicy, and Vercel used vercel-deny-all and vercel-allow-all. Those spellings still work and are deprecated; passing both network and networkPolicy with different values rejects.

snapshot.restore() uses the current connection’s policy, not the captured sandbox’s networking. Saved operations keep the policy resolved at submission when you recover them. Outbound policies do not open a public preview URL; see Preview access.

Pass env at creation to set variables for every command, process and terminal in the sandbox. A per-call env on exec() or processes.start() overrides the same name for that call only:

const box = await client.sandboxes.create({
env: { API_TOKEN: process.env.API_TOKEN!, NODE_ENV: "production" },
});
await box.exec(["node", "app.js"]); // sees API_TOKEN and NODE_ENV=production
await box.exec({ command: { kind: "argv", argv: ["node", "app.js"] }, env: { NODE_ENV: "test" } });

The variables belong to the sandbox: they still apply after sandboxes.get(reference) reopens it in another process, without passing them again. Names match [A-Za-z_][A-Za-z0-9_]*; values are strings without NUL. A request holds at most 128 variables and 64 KiB of names and values. Invalid input rejects with INVALID_ARGUMENT before any provider call, and the message never repeats a name or value. An empty env asks for nothing.

Values are often secrets, so Beachside never writes them into operation references, recovery tokens, telemetry or its own error messages, and adapters redact an echoed value from provider error text. The provider still stores them with the sandbox, and any process inside it can read them.

Provider Create-time env
Daytona Native sandbox env on creation.
E2B Native sandbox envs on creation.
Vercel Sandbox Native session env on creation; persistent sandboxes keep it on resume.
Modal Native sandbox environment, sent with the single create request (experimental).
boxd Unsupported: boxd’s native machine env is not established for exec sessions.

client.capabilities().createEnv reports whether the connection supports it. On a connection that does not, checkCreate({ env }) returns unsupported and create({ env }) rejects with UnsupportedFeatureError before allocating anything; pass the variables per call with exec({ env }) instead. snapshot.restore() does not take env; whether a restored sandbox keeps the source’s variables depends on the provider’s snapshot, so pass them per call if a restored sandbox needs them. Live provider acceptance of create-time variables has not been run.