> ## Documentation Index
> Fetch the complete documentation index at: https://docs.simplesandbox.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Persistent Volumes

> Store and reuse data across sandbox sessions

<Warning>
  **Beta Feature**: Persistent volumes are in beta and currently free (not billed). Pricing will be announced before general availability.
</Warning>

## 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](/quickstart))
* Created a sandbox instance
* Basic understanding of file paths

## Quick start

Mount a volume at `/workspace` to persist your entire project:

```typescript theme={null}
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.
```

<Note>
  Current limitation: **only one volume** per sandbox. Mount your entire workspace at `/workspace` or `/app` to persist everything.
</Note>

## Creating volumes

### Simple volume (1GB default)

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

### Custom volume size

Specify size in gigabytes (1-100 GB):

```typescript theme={null}
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:

```typescript theme={null}
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

```typescript theme={null}
// 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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
// 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

```typescript theme={null}
// ✅ Valid
"my_project"
"workspace_2024"
"app_v2"

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

## Error handling

### Common errors

```typescript theme={null}
// 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

<Tip>
  **Mount at `/workspace` or `/app`**: With one volume per sandbox, mount your entire project to persist code, dependencies, and build artifacts together.
</Tip>

<Tip>
  **Use descriptive names**: Name volumes by project or purpose (`ml_project`, `api_backend`) rather than generic names (`volume1`, `data`).
</Tip>

<Tip>
  **Right-size volumes**: Start with 1-5 GB and increase if needed. Volumes cannot be resized after creation.
</Tip>

<Warning>
  **One volume per sandbox**: You can only mount one volume per sandbox. Choose your mount point carefully.
</Warning>

<Warning>
  **Single attachment**: A volume can only be attached to one sandbox at a time. Delete the sandbox to release the volume.
</Warning>

## 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

<Note>
  Persistent volumes are free during beta. Pricing will be announced before general availability.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="File Operations" icon="file" href="/file-operations">
    Read and write files to mounted volumes
  </Card>

  <Card title="Command Execution" icon="terminal" href="/command-execution">
    Run commands that use persistent storage
  </Card>

  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Get started with the Sandbox SDK
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    Explore the complete API documentation
  </Card>
</CardGroup>
