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

# Create a sandbox from a Compose file

> Start a multi-container sandbox by uploading a Docker Compose file to the sandbox API.

`POST /v1/sandboxes:createFromFile` starts a sandbox from an uploaded file. You send a file type and the file bytes, and the sandbox gateway translates the document into a sandbox spec and runs the same create path as `POST /v1/sandboxes`.

Docker Compose (`SANDBOX_FILE_TYPE_COMPOSE`) is the only accepted file type. Every service in the file becomes a container in a single sandbox, and one service you name becomes the sandbox primary. The gateway doesn't store the file bytes. `GET /v1/sandboxes/{sandboxId}` returns the translated spec.

This isn't Docker Compose equivalence. Before you import an existing project, read [Compose support](#compose-support).

## Before you begin

You need a W\&B API key. See [Get started](/products/sandboxes/serverless/get-started). Send the key in the `x-wandb-api-key` header. To create the sandbox under a W\&B entity other than your default, also send `x-entity-id`.

```bash theme={"system"}
export WANDB_API_KEY="[WANDB-API-KEY]"
```

## Request fields

| Field | Required | Description |
| - | - | - |
| `type` | Yes | Document kind. Use `SANDBOX_FILE_TYPE_COMPOSE`. |
| `contents` | Yes | The file bytes, base64-encoded in JSON. UTF-8, max 256 KiB. |
| `primaryService` | Yes | Service that becomes the sandbox primary. Must name a service in `contents`. No default. |
| `imageOverrides` | No | Per-service image references. Keys must name services in the file. Use this to supply a pullable image for a service that would otherwise need a build. |
| `defaultResources` | Conditional | CPU and memory copied onto each service that omits `deploy.resources`. Per container, not a project budget. GPU here is rejected. Required when the file has more than one service and any service omits `deploy.resources`. |

The request also accepts `maxLifetimeSeconds`, `tags`, `network`, `annotations`, and `requestId`, with the same meaning as on `POST /v1/sandboxes`. `networkIds` returns `UNIMPLEMENTED`.

This field list is closed. Volumes, instance type, runtime class, image-pull credentials, and published services aren't available on this endpoint. Use `POST /v1/sandboxes` when you need them.

## Create the sandbox

Write a Compose file:

```bash title="Write compose.yaml" theme={"system"}
cat > compose.yaml <<'EOF'
services:
  helper:
    image: docker.io/library/busybox:1.36
    command: ["sleep", "3600"]
    expose: ["8080"]
    healthcheck:
      test: ["CMD", "true"]
      interval: 1s
      timeout: 1s
      retries: 3
  main:
    image: docker.io/library/busybox:1.36
    command: ["sleep", "3600"]
    environment:
      HELPER_HOST: helper
    depends_on:
      helper:
        condition: service_healthy
EOF
```

Post it with `contents` base64-encoded:

```bash title="Create a sandbox from compose.yaml" theme={"system"}
jq -n --rawfile yaml compose.yaml '{
  type: "SANDBOX_FILE_TYPE_COMPOSE",
  contents: ($yaml | @base64),
  primaryService: "main",
  defaultResources: { requests: { cpu: "100m", memory: "128Mi" } },
  maxLifetimeSeconds: 3600,
  tags: ["from-file"]
}' | curl -sS -X POST https://api.cwsandbox.com/v1/sandboxes:createFromFile \
  -H "x-wandb-api-key: $WANDB_API_KEY" \
  -H "Content-Type: application/json" \
  -d @-
```

The response is a sandbox in `STATE_CREATING`. Poll its `sandboxId` until it reaches `STATE_RUNNING` or a terminal state:

```bash title="Poll the sandbox" theme={"system"}
export SANDBOX_ID="[SANDBOX-ID]"

curl -sS "https://api.cwsandbox.com/v1/sandboxes/$SANDBOX_ID" \
  -H "x-wandb-api-key: $WANDB_API_KEY"
```

The returned spec has two containers, `main` marked primary, and `HELPER_HOST` still set to `helper`. Inside the sandbox, `helper` resolves to `127.0.0.1`.

To retry a create safely, send `requestId`. The same `requestId` with the same declared inputs returns the existing sandbox. The same `requestId` with different bytes, including a whitespace-only change, returns `ALREADY_EXISTS` with reason `CWSANDBOX_REQUEST_ID_CONFLICT`.

## Compose support

All services share one pod and one network namespace. Service names resolve to `127.0.0.1`, so values such as `HELPER_HOST: helper` and `API_BASE: http://main:8080` work without rewriting the file. The sandbox has no per-service IP addresses, bridge networks, or replicas.

The following behavior differs from Docker Compose:

* **Startup is serial.** Every non-primary service starts one after another, before the primary. Size `maxLifetimeSeconds` for that. A service that never becomes ready leaves the sandbox in `STATE_CREATING`.
* **`RUNNING` tracks the primary only.** A helper that crashes after start doesn't fail the sandbox.
* **`healthcheck` becomes an exec-only startup probe.** `test` must be a string, `CMD`, `CMD-SHELL`, or `NONE`, and durations must be whole seconds. When the probe exhausts its retries, the container is stopped rather than marked unhealthy.
* **Ports stay in the pod.** `expose` and `ports` declare listen ports, but nothing is published externally.
* **Images must be pullable.** Every service needs `image:` in the file or an entry in `imageOverrides`. A service that still needs `build:` returns `UNIMPLEMENTED`.
* **`command` and `entrypoint` follow Docker's shell and exec forms.** Omit them to use the image defaults. Explicit `null` and `[]` are rejected.
* **GPUs are primary-only**, through `deploy.resources.reservations.devices` with the `gpu` capability and a positive integer count.
* **Names must be DNS-1123 labels** (`my-app`, not `My_App`), and can't use the reserved `cw-object-store-agent`, `cw-object-store-agent-restore`, or `dns-egress` prefixes.

### Unsupported keys

The document must be self-contained: the gateway doesn't read your disk and doesn't expand your environment. Unrecognized keys are rejected with the offending field path rather than ignored.

| Rejected | Notes |
| - | - |
| `$VAR` and `${VAR}` interpolation | Write `$$` for a literal `$`. |
| `include`, `extends`, `env_file` | Inline `environment` or `env` only. Bare keys and `null` values are also rejected. |
| `volumes`, `tmpfs`, `configs`, `secrets`, bind mounts | Named-volume projects can't be imported. |
| `restart`, `logging`, `profiles`, `stdin_open`, `tty`, `scale` | Not implemented on this runtime. |
| `network_mode`, `pid`, `ipc`, `extra_hosts`, named networks | One pod, one namespace. |
| Host-to-container port mappings, bind addresses, port ranges, non-TCP protocols, duplicate ports across services | One TCP listen port per entry, unique across the sandbox. |
| `depends_on: service_completed_successfully`, or any `depends_on` targeting the primary | `service_healthy` and `service_started` are supported between non-primary services. |
| Compose memory spellings (`512m`, `2g`, `512mb`) | Use Kubernetes quantities such as `512Mi` or `1Gi`. |
| Named `user` values (`nobody`) | Use a numeric UID. |

The gateway ignores `version`, project `name`, `labels`, and `x-*` extension keys. Don't rely on `labels` reaching the sandbox.

## Common errors

Field violations arrive as `BadRequest` details naming the path and the limit. They don't quote your document.

| Situation | Code and reason | Field |
| - | - | - |
| Omitted `type` | `INVALID_ARGUMENT`, `CWSANDBOX_INVALID_REQUEST` | `type` |
| Type other than Compose | `UNIMPLEMENTED`, `CWSANDBOX_NOT_IMPLEMENTED` | `type` |
| Omitted or unknown `primaryService` | `INVALID_ARGUMENT`, `CWSANDBOX_INVALID_REQUEST` | `primary_service` |
| Service with neither `image:` nor `build:` | `INVALID_ARGUMENT`, `CWSANDBOX_INVALID_REQUEST` | `contents.services.<name>` |
| Service that still needs `build:` | `UNIMPLEMENTED`, `CWSANDBOX_NOT_IMPLEMENTED` | `contents.services.<name>.build` |
| File over 256 KiB, or not a single UTF-8 YAML document | `INVALID_ARGUMENT`, `CWSANDBOX_INVALID_REQUEST` | `contents` |
| Unsupported Compose key | `INVALID_ARGUMENT`, `CWSANDBOX_INVALID_REQUEST` | The key path |
| Same `requestId`, different bytes | `ALREADY_EXISTS`, `CWSANDBOX_REQUEST_ID_CONFLICT` | None |

## See also

* [Get started](/products/sandboxes/serverless/get-started): create your first sandbox from a spec.
* [Sandbox environment variables](/products/sandboxes/serverless/environment-variables): what the platform injects into every container.
