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:
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:
The first run builds the Docker container (2-3 minutes). Subsequent runs are much faster.
Once running, test the endpoints:
Execute a command
File operations
curl http://localhost:8787/run
You should see:
{
"output" : "2 + 2 = 4 \n " ,
"error" : "" ,
"exitCode" : 0 ,
"success" : true
}
{
"content" : "Hello, Sandbox!"
}
Try Python code execution
Modify your Worker to execute Python code. Add this endpoint:
// 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:
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:
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
Docker build takes a long time
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.
Connection refused errors
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 disappear between requests
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' );