Skip to main content
This quickstart guide walks you through creating a simple Worker that executes code and manages files in a sandbox.

Create your project

Create a new project using the minimal template:
npm create cloudflare@latest -- my-sandbox --template=cloudflare/sandbox-sdk/examples/minimal
cd my-sandbox

Understanding the code

Open src/index.ts to see the Worker code:
src/index.ts
import { getSandbox } from '@cloudflare/sandbox';

export { Sandbox } from '@cloudflare/sandbox';

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);

    // Get or create a sandbox instance
    const sandbox = getSandbox(env.Sandbox, 'my-sandbox');

    // Execute a shell command
    if (url.pathname === '/run') {
      const result = await sandbox.exec('echo "2 + 2 = $((2 + 2))"');
      return Response.json({
        output: result.stdout,
        error: result.stderr,
        exitCode: result.exitCode,
        success: result.success
      });
    }

    // Work with files
    if (url.pathname === '/file') {
      await sandbox.writeFile('/workspace/hello.txt', 'Hello, Sandbox!');
      const file = await sandbox.readFile('/workspace/hello.txt');
      return Response.json({
        content: file.content
      });
    }

    return new Response('Try /run or /file');
  }
};
Let’s break down the key parts:

Import the SDK

import { getSandbox } from '@cloudflare/sandbox';
export { Sandbox } from '@cloudflare/sandbox';
  • getSandbox() creates or retrieves a sandbox instance
  • The export { Sandbox } line is required to export the Durable Object class

Get a sandbox instance

const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
  • First argument: The Durable Object namespace from your environment bindings
  • Second argument: A unique ID for this sandbox (determines which container to use)
Use different IDs to create isolated sandboxes. For example, use user IDs to give each user their own sandbox: getSandbox(env.Sandbox, userId)

Execute commands

const result = await sandbox.exec('echo "2 + 2 = $((2 + 2))"');
The exec() method runs shell commands and returns:
  • stdout: Standard output from the command
  • stderr: Standard error output
  • exitCode: The exit code (0 for success)
  • success: Boolean indicating if the command succeeded

Work with files

await sandbox.writeFile('/workspace/hello.txt', 'Hello, Sandbox!');
const file = await sandbox.readFile('/workspace/hello.txt');
  • writeFile() creates or overwrites a file
  • readFile() returns file metadata and contents
  • Files persist across requests to the same sandbox

Run locally

Start the development server:
npm run dev
The first run builds the Docker container (2-3 minutes). Subsequent runs are much faster.
Once running, test the endpoints:
curl http://localhost:8787/run
You should see:
Response from /run
{
  "output": "2 + 2 = 4\n",
  "error": "",
  "exitCode": 0,
  "success": true
}
Response from /file
{
  "content": "Hello, Sandbox!"
}

Try Python code execution

Modify your Worker to execute Python code. Add this endpoint:
src/index.ts
// Add this to your fetch handler
if (url.pathname === '/python') {
  const code = 'print(f"The answer is {2 + 2}")';
  const result = await sandbox.exec(`python3 -c "${code}"`);
  return Response.json({
    output: result.stdout,
    success: result.success
  });
}
Test it:
curl http://localhost:8787/python
{
  "output": "The answer is 4\n",
  "success": true
}

Try the code interpreter

For a better Python experience, use the CodeInterpreter class:
src/index.ts
import { getSandbox, CodeInterpreter } from '@cloudflare/sandbox';

// ... existing code ...

if (url.pathname === '/interpreter') {
  const interpreter = new CodeInterpreter(sandbox);
  
  const result = await interpreter.runCode('python', {
    code: `
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)

plt.plot(x, y)
plt.title('Sine Wave')
plt.savefig('/tmp/plot.png')
print('Plot saved!')
    `.trim()
  });
  
  return Response.json({
    output: result.stdout,
    images: result.images,  // Array of generated images
    success: result.success
  });
}
The CodeInterpreter class:
  • Captures printed output
  • Detects and returns generated images
  • Provides rich execution context
  • Handles common data science workflows

Deploy to production

When you’re ready to deploy:
npx wrangler deploy
After first deployment, wait 2-3 minutes for container provisioning before making requests.
Your Worker will be deployed to Cloudflare’s global network at:
https://my-sandbox.<your-subdomain>.workers.dev

Common patterns

Execute with timeout

const result = await sandbox.exec('sleep 10', {
  timeout: 5000  // Kill after 5 seconds
});

Stream command output

const stream = await sandbox.exec('long-running-command', {
  stream: true
});

for await (const event of stream) {
  if (event.type === 'stdout') {
    console.log('Output:', event.data);
  }
}

Work with sessions

// Create an isolated session with custom environment
const session = await sandbox.createSession({
  env: { MY_VAR: 'custom-value' },
  cwd: '/workspace/project'
});

// Commands in this session use the custom environment
const result = await sandbox.exec('echo $MY_VAR', {
  sessionId: session.id
});

Check if files exist

const files = await sandbox.listFiles('/workspace');
const exists = files.some(f => f.path === '/workspace/hello.txt');

Read binary files

const file = await sandbox.readFile('/workspace/image.png');
const buffer = Buffer.from(file.content, 'base64');

Next steps

API reference

Explore all available methods and options

Execute commands

Learn advanced command execution patterns

Manage files

Work with files and directories

Examples

See real-world applications

Troubleshooting

The first build downloads and configures the base image (2-3 minutes). Subsequent builds are cached and much faster. If you’re using a custom Dockerfile, keep layers minimal to improve build times.
Make sure Docker is running locally. On first deployment to production, wait 2-3 minutes for container provisioning.
The default timeout is 30 seconds. For longer operations, increase the timeout:
await sandbox.exec('long-command', { timeout: 60000 })
Files persist within the same sandbox ID. If you’re using different IDs (or not specifying one), you’ll get different containers. Use consistent IDs:
const sandbox = getSandbox(env.Sandbox, 'my-persistent-sandbox');

Build docs developers (and LLMs) love