Sandbox templates allow you to create customized & reusable sandbox environments. They define the tools, languages, frameworks, and configurations that will be available when you spawn a new sandbox instance.Templates are particularly useful for teams who need standardized environments or for creating many specialized sandboxes for repeated use cases (codegen agent, Git PR reviews agent, etc.).
Initial setup: Follow this guide to create your sandbox template for the first time. This process also creates your first sandbox instance using this template.
Build phase: Your Dockerfile is used to create a container with all required tools and configurations.
Initialization phase: The sandbox API is injected and startup commands are executed.
Instantiation: New sandboxes can be spawned from this template in seconds.
You cannot directly use “library” container images (such as those hosted on Docker Hub and other registries) as sandbox templates. Instead, you must create one or more custom template images for your sandboxes using Dockerfiles and ensure that each template image includes Blaxel’s sandbox API binary. This is necessary for sandbox functionality like process management and file operations.
The Dockerfile is the heart of your template. It defines what will be available in your sandbox environment.
Copy
Ask AI
# Choose a base imageFROM node:22-alpine# Set working directoryWORKDIR /app# Copy sandbox API (required)COPY --from=ghcr.io/blaxel-ai/sandbox:latest /sandbox-api /usr/local/bin/sandbox-api# Install system dependenciesRUN apk update && apk add --no-cache \ git curl python3 make g++ netcat-openbsd \ && rm -rf /var/cache/apk/*# Copy and set up entrypointCOPY entrypoint.sh /entrypoint.shRUN chmod +x /entrypoint.shENTRYPOINT ["/entrypoint.sh"]
Always include the sandbox-api binary from the Blaxel base image. This is required for sandbox functionality like process management and file operations.
The blaxel.toml file defines your template’s runtime configuration:
Copy
Ask AI
name = "mytemplate"type = "sandbox"description = "Full-stack development environment with Node.js and Python"[runtime]generation = "mk3"memory = 8192 # 8GB RAM# Define exposed ports[[runtime.ports]]name = "dev-server"target = 3000protocol = "tcp"[[runtime.ports]]name = "another-api"target = 8888protocol = "tcp"# Set environment variables[env]NODE_ENV = "development"PYTHON_ENV = "development"
Currently, it is not possible to add or update environment variables for a sandbox after it is created. Ensure that any required environment variables are defined in your Dockerfile, your blaxel.toml file, or at sandbox creation time using the Blaxel SDKs.
The entrypoint.sh script runs when a sandbox is created from your template:
Copy
Ask AI
#!/bin/sh# Start the sandbox API (required)/usr/local/bin/sandbox-api &# Wait for sandbox API to be readyecho "Waiting for sandbox API..."while ! nc -z 127.0.0.1 8080; do sleep 0.1doneecho "Sandbox API ready"# Initialize your environmentecho "Setting up development environment..."# Example: Start a development server in the backgroundif [ -f /app/package.json ]; then cd /app npm install # Execute curl command, we execute it through the sandbox-api so that you can access logs, # process status and everything you can do with the sandbox api echo "Running Next.js dev server..." curl http://127.0.0.1:8080/process -X POST -d '{"workingDir": "/app", "command": "npm run dev", "waitForCompletion": false}' -H "Content-Type: application/json"fi# Keep the container runningwait
Before creating the template on Blaxel, test it locally:
Copy
Ask AI
# Build the Docker imagemake build# Run locally to testmake run# Access your sandbox-api on exposed ports# e.g., http://127.0.0.1:8080# Example: curl http://127.0.0.1:8080/process
Once satisfied with your configuration, create the template on Blaxel:
Copy
Ask AI
bl deploy
This will:
Build your Docker image
Push it to Blaxel’s registry (private to your workspace)
Return an image ID you can use for creating sandboxes
Create a first sandbox with that template. It is completely fine to delete the sandbox afterwards, the template will be kept.
You can monitor the template creation:
Copy
Ask AI
bl get sandbox mytemplate --watch
A first sandbox with that template is automatically created on Blaxel upon bl deploy, for you to test in prod-like conditions. You can safely delete the sandbox and keep using the template for new sandboxes.
Although less common, it is also possible to create a sandbox template and sandbox by directly interacting with the Blaxel API.Ensure that you have the following:
Create a directory with the following project contents:
Dockerfile (required) - Defines your custom sandbox image and must include sandbox-api
Any custom scripts (e.g., entrypoint.sh for initialization logic)
Configuration files or data files as needed
Additional dependencies or binaries your sandbox requires
Here is an example of the expected project structure:
Copy
Ask AI
mytemplate/├── Dockerfile # Required - defines your image└── entrypoint.sh # Optional - for custom initialization
The Dockerfile is the heart of your template. It defines what will be available in your sandbox environment. See an example.
The entrypoint.sh script runs when a sandbox is created from your template. See an example.
The Dockerfile can reference and use any files included in the ZIP archive. Everything gets extracted and built together as a Docker image.Once the files are ready, create a ZIP archive containing the files:
Note the upload=true query parameter in the request, which indicates intent to upload custom code.The Blaxel API returns a JSON response. The response contains an x-blaxel-upload-url response header, containing the target URL to use when uploading your template. The URL is in the response headers, not the JSON body.Example response:
Use an HTTP PUT request to upload the ZIP file to the upload URL. Replace the placeholder URL in the command below with the value of the x-blaxel-upload-url response header received earlier.
After uploading, poll the sandbox status endpoint to track the build and deployment progress.Make a GET request to https://api.blaxel.ai/v0/sandboxes/<SANDBOX-NAME>, where SANDBOX-NAME is the metadata.name specified in the initial POST request.
The status field of the response will progress through these values:
Status
Description
UPLOADING
Code archive is being uploaded
BUILDING
Docker image is being built
DEPLOYING
Container is being deployed to the cluster
DEPLOYED
Sandbox is ready to use
FAILED
Deployment failed (check build logs)
DEACTIVATED
Sandbox has been deactivated
Continue polling every 3-5 seconds until the status reaches DEPLOYED or FAILED.A first sandbox with that template is automatically created on Blaxel once deployment succeeds. You can safely delete the sandbox and keep using the template for new sandboxes.
Here’s a complete example script that performs all the steps above:
Copy
Ask AI
#!/bin/bash# Real deployment script that executes the documented API workflowset -e# ConfigurationSANDBOX_NAME="my-custom-sandbox-$(date +%s)"SOURCE_DIR="mytemplate"ZIP_FILE="mytemplate.zip"BASE_URL="https://api.blaxel.ai/v0"# Colors for outputGREEN='\033[0;32m'RED='\033[0;31m'YELLOW='\033[1;33m'BLUE='\033[0;34m'NC='\033[0m' # No Color# Cleanup functioncleanup() { if [ -f "$ZIP_FILE" ]; then rm -f "$ZIP_FILE" echo -e "\n${GREEN}✓ Cleaned up temporary files${NC}" fi}# Set trap to cleanup on exittrap cleanup EXIT# Validate credentialsif [ -z "$BL_API_KEY" ]; then echo -e "${RED}Error: BL_API_KEY not set${NC}" echo "Get your API key from workspace settings and set it with:" echo " export BL_API_KEY='your-api-key'" exit 1fiif [ -z "$BL_WORKSPACE" ]; then echo -e "${RED}Error: BL_WORKSPACE not set${NC}" echo "Set your workspace name with:" echo " export BL_WORKSPACE='your-workspace-name'" exit 1fi# Check if source directory existsif [ ! -d "$SOURCE_DIR" ]; then echo -e "${RED}Error: $SOURCE_DIR directory not found${NC}" exit 1fi# Create ZIP archiveecho -e "${BLUE}Creating ZIP archive from $SOURCE_DIR...${NC}"cd "$SOURCE_DIR"zip -q -r "../${ZIP_FILE}" .cd ..FILE_SIZE=$(wc -c < "$ZIP_FILE" | tr -d ' ')echo -e "${GREEN}✓ ZIP archive created: $ZIP_FILE ($FILE_SIZE bytes)${NC}\n"# Step 1: Create sandbox and get upload URLecho -e "${BLUE}[1/4] Creating sandbox '$SANDBOX_NAME'...${NC}"# Create temporary file for headersHEADERS_FILE=$(mktemp)CREATE_RESPONSE=$(curl -s -D "$HEADERS_FILE" -w "\n%{http_code}" -X POST "$BASE_URL/sandboxes?upload=true" \ -H "Authorization: Bearer $BL_API_KEY" \ -H "X-Blaxel-Workspace: $BL_WORKSPACE" \ -H "Content-Type: application/json" \ -d '{ "apiVersion": "blaxel.ai/v1alpha1", "kind": "Sandbox", "metadata": { "name": "'"$SANDBOX_NAME"'" }, "spec": { "runtime": { "memory": 2048 }, "region": "us-pdx-1" } }')HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n 1)RESPONSE_BODY=$(echo "$CREATE_RESPONSE" | sed '$d')if [ "$HTTP_CODE" != "200" ] && [ "$HTTP_CODE" != "201" ]; then echo -e "${RED}✗ Failed to create sandbox (HTTP $HTTP_CODE)${NC}" echo "$RESPONSE_BODY" | jq . 2>/dev/null || echo "$RESPONSE_BODY" rm -f "$HEADERS_FILE" exit 1fi# Extract upload URL from response headersUPLOAD_URL=$(grep -i "x-blaxel-upload-url:" "$HEADERS_FILE" | cut -d' ' -f2- | tr -d '\r\n')if [ -z "$UPLOAD_URL" ]; then echo -e "${RED}✗ No upload URL received in response headers${NC}" rm -f "$HEADERS_FILE" exit 1firm -f "$HEADERS_FILE"echo -e "${GREEN}✓ Sandbox created${NC}"echo ""# Step 2: Upload ZIP fileecho -e "${BLUE}[2/4] Uploading code archive ($FILE_SIZE bytes)...${NC}"UPLOAD_RESPONSE=$(curl -s -w "%{http_code}" -X PUT "$UPLOAD_URL" \ -H "Content-Type: application/zip" \ --data-binary "@$ZIP_FILE")HTTP_CODE="${UPLOAD_RESPONSE: -3}"if [ "$HTTP_CODE" != "200" ]; then echo -e "${RED}✗ Upload failed with status $HTTP_CODE${NC}" exit 1fiecho -e "${GREEN}✓ Upload completed${NC}"echo ""# Step 3: Monitor deployment statusecho -e "${BLUE}[3/4] Monitoring deployment status...${NC}"MAX_WAIT=900 # 15 minutesSTART_TIME=$(date +%s)LAST_STATUS=""while true; do # Check timeout CURRENT_TIME=$(date +%s) ELAPSED=$((CURRENT_TIME - START_TIME)) if [ $ELAPSED -gt $MAX_WAIT ]; then echo -e "${RED}✗ Deployment timed out after $MAX_WAIT seconds${NC}" exit 1 fi # Get current status STATUS_RESPONSE=$(curl -s -X GET "$BASE_URL/sandboxes/$SANDBOX_NAME" \ -H "Authorization: Bearer $BL_API_KEY" \ -H "X-Blaxel-Workspace: $BL_WORKSPACE") STATUS=$(echo "$STATUS_RESPONSE" | jq -r '.status // empty') if [ -z "$STATUS" ]; then echo -e "${YELLOW}Warning: Could not get status, retrying...${NC}" sleep 3 continue fi # Log status changes if [ "$STATUS" != "$LAST_STATUS" ]; then echo " Status: $STATUS" LAST_STATUS=$STATUS fi # Check terminal states if [ "$STATUS" = "DEPLOYED" ]; then IMAGE=$(echo "$STATUS_RESPONSE" | jq -r '.spec.runtime.image // empty') echo "" echo -e "${GREEN}🎉 Deployment complete!${NC}" echo "Sandbox: $SANDBOX_NAME" echo "Image: $IMAGE" echo "" # Step 4: Show how to use it echo -e "${BLUE}[4/4] How to use your sandbox:${NC}" echo "" echo "Run a command:" echo " bl run sandbox $SANDBOX_NAME" echo "" echo "Get sandbox details:" echo " bl get sandbox $SANDBOX_NAME" echo "" echo "View logs:" echo " bl logs sandbox $SANDBOX_NAME" echo "" echo "Delete sandbox:" echo " bl delete sandbox $SANDBOX_NAME" echo "" exit 0 elif [ "$STATUS" = "FAILED" ]; then echo "" echo -e "${RED}✗ Deployment failed${NC}" echo "" echo "Check build logs with:" echo " curl -X GET '$BASE_URL/sandboxes/$SANDBOX_NAME/build-logs' \\" echo " -H 'Authorization: Bearer \$BL_API_KEY' \\" echo " -H 'X-Blaxel-Workspace: \$BL_WORKSPACE'" exit 1 elif [ "$STATUS" = "DEACTIVATED" ] || [ "$STATUS" = "DEACTIVATING" ] || [ "$STATUS" = "DELETING" ]; then echo "" echo -e "${RED}✗ Unexpected status: $STATUS${NC}" exit 1 fi # Wait before next poll sleep 3done
The script accepts a source directory path containing the Dockerfile and related code and uses it to deploy a sandbox on Blaxel. It monitors the deployment status until completion and also cleans up temporary files.To use this script, first export your API key and credentials as below: