Skip to main content
Beta Feature: Persistent volumes are in beta and currently free (not billed). Pricing will be announced before general availability.

Overview

Persistent volumes store data that survives sandbox restarts. With one volume per sandbox, the recommended approach is to mount your entire workspace.

Prerequisites

  • Installed the Sandbox SDK (see Quickstart)
  • Created a sandbox instance
  • Basic understanding of file paths

Quick start

Mount a volume at /workspace to persist your entire project:
const sandbox = await client.sandboxes.create({
  image: "node:20",
  volumes: {
    "/workspace": "my_project"
  }
});

// Write code
await sandbox.files.write("/workspace/app.js", "console.log('hello')");

// Install dependencies
sandbox.cwd("/workspace");
await sandbox.exec("npm install express");

// Everything persists after deletion
await sandbox.kill();

// Create new sandbox - all files still there
const sandbox2 = await client.sandboxes.create({
  image: "node:20",
  volumes: {
    "/workspace": "my_project"
  }
});

const result = await sandbox2.exec("ls /workspace");
console.log(result.stdout); // Shows app.js, node_modules, etc.
Current limitation: only one volume per sandbox. Mount your entire workspace at /workspace or /app to persist everything.

Creating volumes

Simple volume (1GB default)

const sandbox = await client.sandboxes.create({
  image: "node:20",
  volumes: {
    "/workspace": "my_project"
  }
});

Custom volume size

Specify size in gigabytes (1-100 GB):
const sandbox = await client.sandboxes.create({
  image: "node:20",
  volumes: {
    "/workspace": {
      name: "my_project",
      sizeGb: 10
    }
  }
});

Volume lifecycle

  1. Create: Volume is created automatically on first use
  2. Persist: Data remains after sandbox deletion
  3. Reuse: Mount by name in new sandboxes
  4. Delete: Explicitly delete when no longer needed

Common workflows

Full workspace persistence

Mount at /workspace to persist code, dependencies, and build artifacts:
const sandbox = await client.sandboxes.create({
  image: "node:20",
  volumes: { "/workspace": "my_app" }
});

sandbox.cwd("/workspace");
await sandbox.exec("git clone https://github.com/user/repo.git .");
await sandbox.exec("npm install");
await sandbox.exec("npm run build");
await sandbox.kill();

// Later: everything is still there
const sandbox2 = await client.sandboxes.create({
  image: "node:20",
  volumes: { "/workspace": "my_app" }
});

sandbox2.cwd("/workspace");
await sandbox2.exec("npm test");  // No reinstall needed

Iterative development

// Day 1: Setup
const sandbox = await client.sandboxes.create({
  image: "python:3.11",
  volumes: { "/app": "ml_project" }
});

sandbox.cwd("/app");
await sandbox.exec("pip install torch numpy pandas");
await sandbox.files.write("/app/train.py", pythonCode);
await sandbox.kill();

// Day 2: Continue where you left off
const sandbox2 = await client.sandboxes.create({
  image: "python:3.11",
  volumes: { "/app": "ml_project" }
});

sandbox2.cwd("/app");
await sandbox2.exec("python train.py");  // All deps already installed

Database persistence

For services that only need data storage:
const sandbox = await client.sandboxes.create({
  image: "postgres:16",
  volumes: {
    "/var/lib/postgresql/data": {
      name: "postgres_data",
      sizeGb: 10
    }
  },
  env: {
    POSTGRES_PASSWORD: "secret",
    POSTGRES_DB: "myapp"
  }
});

await sandbox.exec(
  "docker-entrypoint.sh postgres >/tmp/postgres.log 2>&1",
  { background: true }
);

Volume management

Volume attachment

Only one sandbox can use a volume at a time:
const sandbox1 = await client.sandboxes.create({
  image: "node:20",
  volumes: { "/workspace": "shared_vol" }
});

// This fails - volume already attached
try {
  const sandbox2 = await client.sandboxes.create({
    image: "node:20",
    volumes: { "/workspace": "shared_vol" }
  });
} catch (error) {
  // Error: Volume "shared_vol" is already attached
}

// Release volume by deleting sandbox
await sandbox1.kill();

// Now it works
const sandbox2 = await client.sandboxes.create({
  image: "node:20",
  volumes: { "/workspace": "shared_vol" }
});

Regional constraints

Volumes and sandboxes must be in the same region:
// Volume created in IAD
const sandbox1 = await client.sandboxes.create({
  image: "node:20",
  volumes: { "/workspace": "my_vol" }
});

// This fails - different region
try {
  const sandbox2 = await client.sandboxes.create({
    image: "node:20",
    region: "lax",
    volumes: { "/workspace": "my_vol" }
  });
} catch (error) {
  // Error: Volume "my_vol" is in region iad
}

Volume naming rules

  • Lowercase letters, numbers, and underscores only
  • Maximum 30 characters
// ✅ Valid
"my_project"
"workspace_2024"
"app_v2"

// ❌ Invalid
"My-Project"  // No uppercase or hyphens
"cache@v2"    // No special characters

Error handling

Common errors

// Invalid name
try {
  await client.sandboxes.create({
    image: "node:20",
    volumes: { "/workspace": "my-project" }  // Hyphen not allowed
  });
} catch (error) {
  // "Volume name must be lowercase alphanumeric and underscores"
}

// Size limit exceeded
try {
  await client.sandboxes.create({
    image: "node:20",
    volumes: {
      "/workspace": { name: "big_vol", sizeGb: 500 }  // Max is 100
    }
  });
} catch (error) {
  // "Size must be 1-100 GB"
}

// Multiple volumes
try {
  await client.sandboxes.create({
    image: "node:20",
    volumes: {
      "/workspace": "vol1",
      "/cache": "vol2"  // Only one volume allowed
    }
  });
} catch (error) {
  // "Only one volume can be mounted per sandbox"
}

Best practices

Mount at /workspace or /app: With one volume per sandbox, mount your entire project to persist code, dependencies, and build artifacts together.
Use descriptive names: Name volumes by project or purpose (ml_project, api_backend) rather than generic names (volume1, data).
Right-size volumes: Start with 1-5 GB and increase if needed. Volumes cannot be resized after creation.
One volume per sandbox: You can only mount one volume per sandbox. Choose your mount point carefully.
Single attachment: A volume can only be attached to one sandbox at a time. Delete the sandbox to release the volume.

Limitations

  • One volume per sandbox: Current limitation
  • Size range: 1-100 GB per volume
  • Regional binding: Volumes cannot move between regions
  • Single attachment: One volume attached to one sandbox at a time
  • No resizing: Volume size is fixed at creation
  • Beta feature: Not currently billed (pricing TBA before GA)

Pricing

Persistent volumes are free during beta. Pricing will be announced before general availability.

Next steps