Skip to content

2026 deprecation migration guide

Last updated View as MarkdownAgent setup

This guide walks through migrating away from Sandbox SDK features deprecated in the deprecation announcement. Do not build new work on these APIs. Finish this cleanup on the stable package, then move to the 1.0 preview when you can.

For the announcement and rationale, refer to the deprecation changelog entry.

Before you migrate

Update to the latest Sandbox SDK release before changing transport or session configuration. If your project uses a version earlier than 0.9.1, deploy a newer @cloudflare/sandbox package and container image before switching to RPC transport. Session isolation with enableDefaultSession: false requires Sandbox SDK 0.10.3 or newer — on 0.9.10.10.2, upgrade first, then set the flag.

Search your codebase for deprecated configuration and APIs:

rg 'SANDBOX_TRANSPORT|transport:|exposePort\(|enableDefaultSession|execStream\(|readFileStream|writeFileStream'

Also review any code that uses stream-specific file helpers or depends on shell state carrying across separate exec() calls.

HTTP and WebSocket transports

HTTP and WebSocket transports are deprecated. Switch to the RPC transport.

To configure RPC transport for every sandbox in your Worker, set SANDBOX_TRANSPORT in your Worker's configuration:

{
	"vars": {
		"SANDBOX_TRANSPORT": "rpc"
	}
}
[vars]
SANDBOX_TRANSPORT = "rpc"

To configure RPC transport for a specific sandbox, pass transport: "rpc" to getSandbox():

import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "user-123", {
	transport: "rpc",
});
import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "user-123", {
	transport: "rpc",
});

For more information, refer to Transport modes.

Desktop

The desktop feature was removed in 0.10.2. The feature ran a full Linux desktop inside the sandbox for computer-use style automation. If you still need that shape, rebuild it with extensions rather than a built-in desktop API. Keep Sandbox SDK for isolated command execution, file operations, and runtime workflows that do not require an in-sandbox desktop.

Expose ports

Replace exposePort() with the tunnels API for public URLs. The tunnels API requires RPC transport.

Use quick tunnels for development, demos, and short-lived URLs. Use named tunnels for production traffic, webhook receivers, OAuth callbacks, and stable hostnames on a zone you control.

import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "my-sandbox", {
	transport: "rpc",
});

const server = await sandbox.startProcess("python -m http.server 8080");
await server.waitForPort(8080);

const tunnel = await sandbox.tunnels.get(8080);
return Response.json({ url: tunnel.url });
import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "my-sandbox", {
	transport: "rpc",
});

const server = await sandbox.startProcess("python -m http.server 8080");
await server.waitForPort(8080);

const tunnel = await sandbox.tunnels.get(8080);
return Response.json({ url: tunnel.url });

If your exposePort() flow used proxyToSandbox() to inject authentication or rewrite responses, account for that behavior before moving the public URL to a tunnel.

For more information, refer to Tunnels and Expose services.

Default sessions

Set enableDefaultSession: false on getSandbox(). Operations without an explicit session will then run in isolation and will not inherit shell state from earlier calls.

import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "user-123", {
	enableDefaultSession: false,
	transport: "rpc",
});
import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "user-123", {
	enableDefaultSession: false,
	transport: "rpc",
});

If your code expects commands like cd /workspace/app to affect later exec() calls, create an explicit session and run related commands through that session:

const buildSession = await sandbox.createSession({
	id: "build",
	cwd: "/workspace/app",
});

await buildSession.exec("npm install");
await buildSession.exec("npm test");
const buildSession = await sandbox.createSession({
	id: "build",
	cwd: "/workspace/app",
});

await buildSession.exec("npm install");
await buildSession.exec("npm test");

For one-off commands, pass cwd or env directly to exec() instead of relying on persisted shell state:

await sandbox.exec("npm test", {
	cwd: "/workspace/app",
	env: {
		NODE_ENV: "test",
	},
});
await sandbox.exec("npm test", {
	cwd: "/workspace/app",
	env: {
		NODE_ENV: "test",
	},
});

For more information, refer to Sandbox options and Sessions.

Streaming APIs

The Sandbox SDK is consolidating separate streaming APIs into the base exec(), readFile(), and writeFile() methods. Audit code that depends on stream-specific helpers and move to the base APIs where they support streaming behavior.

For command output, use exec() with streaming callbacks:

await sandbox.exec("npm install", {
	stream: true,
	onOutput: (stream, data) => {
		console.log(`[${stream}] ${data}`);
	},
});
await sandbox.exec("npm install", {
	stream: true,
	onOutput: (stream, data) => {
		console.log(`[${stream}] ${data}`);
	},
});

For large or binary files, use the base file APIs with RPC transport. Pass a ReadableStream to writeFile(), or read a file as a stream with encoding: "none":

const request = await fetch("https://example.com/archive.tar.gz");

if (!request.body) {
	throw new Error("Expected archive response body");
}

await sandbox.writeFile("/workspace/archive.tar.gz", request.body);

const file = await sandbox.readFile("/workspace/archive.tar.gz", {
	encoding: "none",
});

return new Response(file.content, {
	headers: { "Content-Type": file.mimeType },
});
const request = await fetch("https://example.com/archive.tar.gz");

if (!request.body) {
	throw new Error("Expected archive response body");
}

await sandbox.writeFile("/workspace/archive.tar.gz", request.body);

const file = await sandbox.readFile("/workspace/archive.tar.gz", {
	encoding: "none",
});

return new Response(file.content, {
	headers: { "Content-Type": file.mimeType },
});

For more information, refer to Commands and Files.

Verify the migration

Use this checklist before you depend on a Sandbox SDK release that has removed the deprecated APIs:

  • RPC transport is configured with SANDBOX_TRANSPORT=rpc or transport: "rpc".
  • No websocket or http transport configuration remains.
  • No exposePort() usage remains in the migrated path.
  • enableDefaultSession is set to false.
  • Stateful command workflows use sandbox.createSession().
  • One-off commands pass cwd and env directly.
  • Streaming file and command code uses the base APIs.
  • Your Worker has been deployed and smoke-tested.

Coding agents

Coding agents with Cloudflare Skills installed (Agent setup) should use sandbox-stable for work on the current stable package and follow this guide for deprecated-API cleanup while staying on stable. For a full move to Sandbox SDK 1.0 (@next), use sandbox-migrate-to-next (and the 1.0 migrate guide) instead.

1.0 preview

After you finish the stable-line changes in this guide, move on to the Sandbox SDK 1.0 preview on @cloudflare/sandbox@next when you can. That preview is the path to the next stable major release.

Refer to Sandbox SDK 1.0 preview and Migrate to the 1.0 preview.

Was this helpful?