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

# Overview

> What sandboxes are and how to configure them

A sandbox is a local microVM with its own Linux kernel, filesystem, and network stack. Your application or the `msb` CLI starts it as a child process, then talks to the guest agent to run commands, move files, and control lifecycle.

The security boundary is hardware virtualization, not Linux namespaces. That makes sandboxes a good fit for untrusted workloads: user-submitted code, AI agent actions, plugins, dependency installs, CI jobs, scrapers, and tools that should not inherit the host process's full privileges.

## Create a sandbox

At minimum, a sandbox needs a name and an image. Everything else has defaults: 1 vCPU, 512 MiB memory, public-only networking, and `/bin/sh` as the default shell.

<CodeGroup>
  ```rust Rust theme={null}
  let sb = Sandbox::builder("worker")
      .image("python")
      .create()
      .await?;
  ```

  ```typescript TypeScript theme={null}
  await using sb = await Sandbox.builder("worker")
      .image("python")
      .create();
  ```

  ```python Python theme={null}
  sb = await Sandbox.create("worker", image="python")
  ```

  ```go Go theme={null}
  sb, err := m.CreateSandbox(ctx, "worker", m.WithImage("python"))
  ```

  ```bash CLI theme={null}
  msb create python --name worker
  ```
</CodeGroup>

Sandbox names must be non-empty and no longer than 128 UTF-8 bytes.

## Common configuration

<CodeGroup>
  ```rust Rust theme={null}
  let sb = Sandbox::builder("worker")
      .image("python")
      .memory(1024)
      .cpus(2)
      .env("DEBUG", "true")
      .label("user.id", "alice")
      .volume("/app/src", |v| v.bind("./src").readonly())
      .create()
      .await?;
  ```

  ```typescript TypeScript theme={null}
  await using sb = await Sandbox.builder("worker")
      .image("python")
      .memory(1024)
      .cpus(2)
      .env("DEBUG", "true")
      .label("user.id", "alice")
      .volume("/app/src", (m) => m.bind("./src").readonly())
      .create();
  ```

  ```python Python theme={null}
  sb = await Sandbox.create(
      "worker",
      image="python",
      memory=1024,
      cpus=2,
      env={"DEBUG": "true"},
      labels={"user.id": "alice"},
      volumes={"/app/src": Volume.bind("./src", readonly=True)},
  )
  ```

  ```go Go theme={null}
  sb, err := m.CreateSandbox(ctx, "worker",
      m.WithImage("python"),
      m.WithMemory(1024),
      m.WithCPUs(2),
      m.WithEnv(map[string]string{"DEBUG": "true"}),
      m.WithLabels(map[string]string{"user.id": "alice"}),
      m.WithMounts(map[string]m.MountConfig{
          "/app/src": m.Mount.Bind("./src", m.MountOptions{Readonly: true}),
      }),
  )
  ```

  ```bash CLI theme={null}
  msb create python --name worker \
    -c 2 \
    -m 1G \
    -e DEBUG=true \
    --label user.id=alice \
    -v ./src:/app/src:ro
  ```
</CodeGroup>

| Option    | Default       | Description                                 |
| --------- | ------------- | ------------------------------------------- |
| `image`   | required      | OCI image, local rootfs path, or disk image |
| `cpus`    | `1`           | Virtual CPU limit                           |
| `memory`  | `512`         | Guest memory limit in MiB                   |
| `workdir` | image default | Default working directory for commands      |
| `shell`   | `/bin/sh`     | Shell used by `shell()` calls               |
| `env`     | empty         | Environment variables                       |
| `labels`  | empty         | Key/value metadata for metric attribution   |
| `volumes` | empty         | Bind, named, tmpfs, or disk-image mounts    |
| `network` | public-only   | Network policy and published ports          |
| `scripts` | empty         | Named scripts mounted at `/.msb/scripts/`   |

Labels are arbitrary `key=value` metadata attached to a sandbox, set at creation
and fixed for the sandbox's life. They are meant for attribution — tagging a
sandbox with the user, tenant, or environment it belongs to so the metrics
pipeline can build per-user views. Keys cannot start with the reserved prefixes
`sandbox.`, `microsandbox.`, or `service.`.

Set one at a time with `.label(key, value)` or many at once with
`.labels({...})` (`WithLabel` / `WithLabels` in Go, the `labels={...}` argument
in Python). On the CLI, repeat `--label` once per entry. Values may be empty: a
valueless label such as `--label gpu` is a plain marker (it stores `gpu=""`),
matching Docker's label semantics.

The OCI image's own labels (`LABEL` instructions, `org.opencontainers.image.*`,
etc.) are imported automatically as sandbox labels at create time. A label you
set yourself overrides the image's value on a key collision. Image labels using
a reserved prefix are skipped. Note this can add series cardinality if an image
carries high-cardinality labels (a commit SHA, a build timestamp); set
`--no-labels` on `msb-metrics` if that is a concern.

### Selecting sandboxes by label

Labels double as selectors. `list_with` returns sandboxes carrying **all** of
the given labels (AND-matched) — useful when your application owns a subset of
sandboxes on a shared host. The CLI extends this to bulk operations: `msb stop`,
`msb start`, and `msb rm` all accept `--label` to act on every match.

<CodeGroup>
  ```rust Rust theme={null}
  use microsandbox::sandbox::{Sandbox, SandboxFilter};

  let mine = Sandbox::list_with(SandboxFilter::new().label("app", "engine")).await?;
  ```

  ```typescript TypeScript theme={null}
  const mine = await Sandbox.listWith({ labels: { app: "engine" } });
  ```

  ```python Python theme={null}
  mine = await Sandbox.list_with(labels={"app": "engine"})
  ```

  ```go Go theme={null}
  mine, err := microsandbox.ListSandboxesWith(ctx,
      microsandbox.NewSandboxFilter().WithLabels(map[string]string{"app": "engine"}))
  ```

  ```bash CLI theme={null}
  msb ls --label app=engine      # list matches
  msb stop --label app=engine    # stop every match
  msb rm --force --label app=engine
  ```
</CodeGroup>

<Tip>
  `cpus` and `memory` are limits, not reservations. Guest memory is allocated as the VM touches pages.
</Tip>

## Image sources

Most sandboxes start from an OCI image:

```bash theme={null}
msb create python --name worker
```

You can also use a host directory as the root filesystem:

```bash theme={null}
msb create ./my-rootfs --name worker
```

Or boot from a disk image:

```bash theme={null}
msb create ./alpine.qcow2 --name worker
```

OCI images use a copy-on-write overlay so sandboxes can share cached base layers. Disk images are attached as block devices, so each sandbox should use its own disk image copy unless the image format handles its own snapshotting.

See [Images](/images/overview) and [Disk Images](/images/disk-images) for the full image model.

## Naming conflicts

Creating a sandbox fails if another sandbox already has the same name. Use replace when you want a fresh sandbox with that name:

<CodeGroup>
  ```rust Rust theme={null}
  let sb = Sandbox::builder("worker")
      .image("python")
      .replace()
      .create()
      .await?;
  ```

  ```typescript TypeScript theme={null}
  await using sb = await Sandbox.builder("worker")
      .image("python")
      .replace()
      .create();
  ```

  ```python Python theme={null}
  sb = await Sandbox.create("worker", image="python", replace=True)
  ```

  ```go Go theme={null}
  sb, err := m.CreateSandbox(ctx, "worker",
      m.WithImage("python"),
      m.WithReplace(),
  )
  ```

  ```bash CLI theme={null}
  msb create --replace python --name worker
  ```
</CodeGroup>

When replacing a running sandbox, microsandbox attempts graceful shutdown before force-killing it. Use `replace_with_timeout` or `--replace-with-timeout` when the workload needs a longer grace period.

## Where to go next

* [Lifecycle](/sandboxes/lifecycle): start, stop, detach, wait, and remove sandboxes
* [Commands](/sandboxes/commands): run commands and stream output
* [Volumes](/sandboxes/volumes): persist or share data
* [Networking](/networking/overview): control egress, ingress, DNS, and ports
* [Customize](/sandboxes/customize): add scripts, patches, or a custom init
* [SDK reference](/sdk/overview): per-language API details
