> Agent-readable docs index: /llms.txt. Full docs in one file: /llms-full.txt. Download /docs.zip to grep all markdown files locally.

---
title: "Elasticity"
description: "Dynamically scale sandbox memory and CPU — automatically, manually, or via the in-VM API"
---

A sandbox's memory and CPU can be resized at runtime. The platform's recommended path is **Autoscaling** — opt the sandbox in once and we resize it for you based on observed memory pressure. Lower-level controls are also available if you want to drive sizing yourself or freeze it.

CPU scales proportionally to memory in all modes (1 vCPU per \~4 GB up to 16 GB / 4 vCPU). The permissible memory tiers are:

| Memory | vCPU            |
| ------ | --------------- |
| 1 GB   | 1 (best-effort) |
| 4 GB   | 1               |
| 8 GB   | 2               |
| 16 GB  | 4               |

If you want a sandbox to **stay at a fixed size**, see [Locking Resources](#locking-resources).

## Autoscaling

Opt a sandbox into the per-sandbox autoscaler and the platform resizes it for you based on observed memory pressure. Autoscale is **opt-in per sandbox** and **disabled by default**.

This is the recommended way to size a sandbox: turn it on once with bounds you're comfortable with, then leave it. Manual `scale` and the in-VM API are escape hatches for cases where the autoscaler isn't a good fit (e.g. you want a hard guarantee for a benchmark, or you're scripting your own logic).

### Enable

<Tabs items={["TypeScript", "Python", "CLI", "HTTP"]}>
  <Tab title="TypeScript">
    ```typescript
    await sandbox.setAutoscale({
      enabled: true,
      minMemoryMB: 1024,
      maxMemoryMB: 16384,
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python
    await sandbox.set_autoscale(
        enabled=True,
        min_memory_mb=1024,
        max_memory_mb=16384,
    )
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    oc sandbox autoscale sb-abc123 --on --min 1024 --max 16384
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash
    curl -sf -X PUT "$API/api/sandboxes/$SANDBOX_ID/autoscale" \
      -H "X-API-Key: $API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"enabled": true, "minMemoryMB": 1024, "maxMemoryMB": 16384}'
    ```
  </Tab>
</Tabs>

`minMemoryMB` and `maxMemoryMB` must be values from the tier table above. The autoscaler keeps the sandbox between these bounds, in tier steps.

### Behavior

* **Scale up**: when the sandbox's 1-minute average memory utilization exceeds 75 %, jump to the next tier. 60-second cooldown between up-events.
* **Scale down**: when **all** of the 1-min, 5-min, and 15-min utilization averages stay below 25 %, drop one tier. 5-minute cooldown between down-events. Down requires at least 15 minutes of low-utilization data, so a brief idle pause won't shrink you.
* **Manual override**: any explicit `scale` call disables autoscale on that sandbox. Re-enable explicitly via `setAutoscale({ enabled: true, ... })` (or the equivalent in any SDK) if you want it back.

### Disable

<Tabs items={["TypeScript", "Python", "CLI", "HTTP"]}>
  <Tab title="TypeScript">
    ```typescript
    await sandbox.setAutoscale({ enabled: false });
    ```
  </Tab>

  <Tab title="Python">
    ```python
    await sandbox.set_autoscale(enabled=False)
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    oc sandbox autoscale sb-abc123 --off
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash
    curl -sf -X PUT "$API/api/sandboxes/$SANDBOX_ID/autoscale" \
      -H "X-API-Key: $API_KEY" \
      -d '{"enabled": false}'
    ```
  </Tab>
</Tabs>

### Inspect

<Tabs items={["TypeScript", "Python", "CLI", "HTTP"]}>
  <Tab title="TypeScript">
    ```typescript
    const cfg = await sandbox.getAutoscale();
    // { sandboxID: "sb-...", enabled: true, minMemoryMB: 1024, maxMemoryMB: 16384 }
    ```
  </Tab>

  <Tab title="Python">
    ```python
    cfg = await sandbox.get_autoscale()
    # {"sandboxID": "sb-...", "enabled": True, "minMemoryMB": 1024, "maxMemoryMB": 16384}
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    oc sandbox autoscale sb-abc123
    # Autoscale enabled for sb-abc123 (1024–16384 MB)
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash
    curl -sf "$API/api/sandboxes/$SANDBOX_ID/autoscale" -H "X-API-Key: $API_KEY"
    # {"sandboxID":"sb-...","enabled":true,"minMemoryMB":1024,"maxMemoryMB":16384}
    ```
  </Tab>
</Tabs>

## Manual Scaling (Control Plane)

When you want to resize once — predictable size for a benchmark, a one-off scale-up before a known-heavy task, an operator response to an alert — call `scale` from your application or operator tooling:

<Tabs items={["TypeScript", "Python", "CLI", "HTTP"]}>
  <Tab title="TypeScript">
    ```typescript
    await sandbox.scale({ memoryMB: 4096 });
    ```
  </Tab>

  <Tab title="Python">
    ```python
    await sandbox.scale(memory_mb=4096)
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    oc sandbox scale sb-abc123 4096
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash
    curl -sf -X POST "$API/api/sandboxes/$SANDBOX_ID/scale" \
      -H "X-API-Key: $API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"memoryMB": 4096}'
    ```
  </Tab>
</Tabs>

A manual scale **disables autoscale** on the sandbox — explicit user intent overrides the loop. Re-enable it later if you want size to track load again.

The endpoint can return:

* **403 `scaling_locked`** — the sandbox is locked. See [Locking Resources](#locking-resources).
* **409 `oom_floor`** — the requested size would force a guest OOM-kill because the current working set exceeds it. Free memory inside the guest, then retry.
* **402 Payment Required** — the requested size exceeds your plan cap.

## In-VM Scaling

Sandboxes expose an internal metadata API at `http://169.254.169.254` that lets code **inside** the VM scale itself. Useful for workload-aware scripts where the workload knows its own demand better than the platform autoscaler can infer (e.g. "scale up before this build, back down after").

<Note>
  This endpoint is only reachable from inside the sandbox. It is not exposed through the control plane API or SDKs.
</Note>

### Scale Memory

Send a `POST` to `/v1/scale` with the desired memory in MB. CPU is adjusted proportionally.

```bash
curl -s -X POST http://169.254.169.254/v1/scale \
  -H "Content-Type: application/json" \
  -d '{"memoryMB": 4096}'
```

### Check Current Limits

```bash
curl -s http://169.254.169.254/v1/limits
```

### Example: Rust Compilation

Rust builds are memory-hungry. You can alias `cargo` to scale up before compilation and scale back down after:

```bash
alias cargo='_cargo_scaled'
_cargo_scaled() {
  # Scale up to 16GB / 4 vCPU before build
  curl -sf -X POST http://169.254.169.254/v1/scale \
    -H "Content-Type: application/json" -d '{"memoryMB": 16384}'

  # Run the actual cargo command
  command cargo "$@"
  local exit_code=$?

  # Scale back down to 4GB / 1 vCPU
  curl -sf -X POST http://169.254.169.254/v1/scale \
    -H "Content-Type: application/json" -d '{"memoryMB": 4096}'

  return $exit_code
}
```

Add this to your sandbox's `~/.bashrc` or inject it via `sandbox.exec.run` so every `cargo build`, `cargo test`, etc. automatically gets the extra resources.

### Example: Custom Scaling Loop

A simple shell script that monitors memory pressure and scales automatically. Useful when you want fine-grained control inside the sandbox itself; for the platform-managed equivalent see [Autoscaling](#autoscaling) above.

```bash
#!/bin/sh
SCALE_API="http://169.254.169.254/v1/scale"
MIN_MB=1024
MAX_MB=8192
SCALE_UP_THRESHOLD=80
SCALE_DOWN_THRESHOLD=30
COOLDOWN=30
last_scale=0

while true; do
  mem_total=$(awk '/MemTotal/{print $2}' /proc/meminfo)
  mem_avail=$(awk '/MemAvailable/{print $2}' /proc/meminfo)
  usage_pct=$(( (mem_total - mem_avail) * 100 / mem_total ))
  total_mb=$((mem_total / 1024))
  now=$(date +%s)
  elapsed=$((now - last_scale))

  if [ $usage_pct -gt $SCALE_UP_THRESHOLD ] && [ $elapsed -gt $COOLDOWN ]; then
    new_mb=$((total_mb * 2))
    [ $new_mb -gt $MAX_MB ] && new_mb=$MAX_MB
    if [ $new_mb -gt $total_mb ]; then
      echo "usage=$usage_pct% -> scaling UP to ${new_mb}MB"
      curl -sf -X POST "$SCALE_API" \
        -H "Content-Type: application/json" \
        -d "{\"memoryMB\":$new_mb}"
      last_scale=$now
    fi
  elif [ $usage_pct -lt $SCALE_DOWN_THRESHOLD ] && [ $total_mb -gt $MIN_MB ] && [ $elapsed -gt $COOLDOWN ]; then
    new_mb=$((total_mb / 2))
    [ $new_mb -lt $MIN_MB ] && new_mb=$MIN_MB
    if [ $new_mb -lt $total_mb ]; then
      echo "usage=$usage_pct% -> scaling DOWN to ${new_mb}MB"
      curl -sf -X POST "$SCALE_API" \
        -H "Content-Type: application/json" \
        -d "{\"memoryMB\":$new_mb}"
      last_scale=$now
    fi
  fi

  sleep 5
done
```

## Locking Resources

If you want a sandbox to **stay at a fixed size** — predictable billing, a benchmark, a long-running pinned workload — lock it. Locking blocks both manual scaling and autoscaling on the sandbox.

<Tabs items={["TypeScript", "Python", "CLI", "HTTP"]}>
  <Tab title="TypeScript">
    ```typescript
    await sandbox.setScalingLock(true);
    ```
  </Tab>

  <Tab title="Python">
    ```python
    await sandbox.set_scaling_lock(True)
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    oc sandbox lock sb-abc123
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash
    curl -sf -X PUT "$API/api/sandboxes/$SANDBOX_ID/scaling-lock" \
      -H "X-API-Key: $API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"locked": true}'
    ```
  </Tab>
</Tabs>

While locked:

* `scale` returns **403** `scaling_locked`
* `setAutoscale({ enabled: true })` returns **403** `scaling_locked`
* The autoscaler skips the sandbox

Locking automatically disables autoscale on the sandbox, so you have a single user-facing toggle. Unlocking does **not** auto-re-enable autoscale; turn it back on explicitly if you want it.

<Tabs items={["TypeScript", "Python", "CLI", "HTTP"]}>
  <Tab title="TypeScript">
    ```typescript
    // Unlock
    await sandbox.setScalingLock(false);

    // Inspect
    const lock = await sandbox.getScalingLock();
    // { sandboxID: "sb-...", locked: false }
    ```
  </Tab>

  <Tab title="Python">
    ```python
    # Unlock
    await sandbox.set_scaling_lock(False)

    # Inspect
    lock = await sandbox.get_scaling_lock()
    # {"sandboxID": "sb-...", "locked": False}
    ```
  </Tab>

  <Tab title="CLI">
    ```bash
    oc sandbox unlock sb-abc123
    oc sandbox lock-status sb-abc123
    ```
  </Tab>

  <Tab title="HTTP">
    ```bash
    # Unlock
    curl -sf -X PUT "$API/api/sandboxes/$SANDBOX_ID/scaling-lock" \
      -H "X-API-Key: $API_KEY" \
      -d '{"locked": false}'

    # Inspect
    curl -sf "$API/api/sandboxes/$SANDBOX_ID/scaling-lock" -H "X-API-Key: $API_KEY"
    # {"sandboxID":"sb-...","locked":false}
    ```
  </Tab>
</Tabs>
