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

# BuildSpec reference

> How to describe a template's base image, build steps, and runtime defaults

A `BuildSpec` is the canonical declaration of how to build a template. The SDK flattens it onto `TemplateCreateOptions` for convenience: `from` / `steps` / `startCmd` / `readyCmd` are top-level options.

## `from`: base image

An OCI image reference. Resolved to a digest at build time for reproducibility.

```typescript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
from: "python:3.11" // Docker Hub
from: "ghcr.io/myorg/foo:v1" // any OCI registry
```

**Constraints:**

* Must be a **linux/amd64** image
* **Alpine bases are rejected**
* **Distroless bases are rejected** — they ship no shell, so `run` steps can't execute

## `steps`: ordered build steps

A list of tagged objects executed in order inside the build VM. Exactly one of `run` / `env` / `workdir` / `user` must be set per step.

### `run`: shell command

```typescript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
{
  run: "pip install -r requirements.txt"
}
```

Wrapped in `/bin/sh -c` inside the build VM.

### `env`: environment variable

```typescript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
{ env: { key: "DEBUG", value: "1" } }
```

Sets an env var for subsequent build steps AND as a runtime default. Caller-supplied `envVars` on sandbox create override on conflict.

### `workdir`: working directory

```typescript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
{
  workdir: "/srv/app"
}
```

Working directory for subsequent build steps and the runtime default cwd. Auto-created and chowned to the current build user. Per-exec `workingDir` overrides at runtime.

### `user`: switch user

```typescript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
{ user: { name: "appuser", sudo: true } }
```

Switches the user for subsequent build steps and sets the runtime default exec user. User is created if not present. `sudo: true` grants passwordless sudo.

## `startCmd`: process to start after build

```typescript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
startCmd: "python server.py"
```

The snapshot captures the running process, so sandboxes restored from this template come up with it already live.

## `readyCmd`: readiness probe

```typescript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
readyCmd: "curl -f http://localhost:8080/health"
```

Polled every 2s after `startCmd` until it exits `0` or 10 minutes elapse. Use this to wait for a server to bind its port before snapshotting.

## Resource limits

Templates specify the VM shape; sandboxes inherit these and cannot override them per-sandbox.

| Field       | Min  | Max  | Default |
| ----------- | ---- | ---- | ------- |
| `vcpu`      | 1    | 4    | 1       |
| `memoryMib` | 256  | 4096 | 1024    |
| `diskMib`   | 1024 | 8192 | 4096    |

The **Max** column is the platform ceiling. New teams start with a lower per-team cap (2 vCPU, 2048 MiB memory); email [support@superserve.ai](mailto:support@superserve.ai) to raise it.

## Build error codes

When a build lands on `failed`, `BuildError.code` carries one of these stable identifiers (the SDK parses it from the `"<code>: <detail>"` prefix on `errorMessage`):

| Code                   | Meaning                                                                                      |
| ---------------------- | -------------------------------------------------------------------------------------------- |
| `bad_reference`        | The `from` image reference is malformed (expected `python:3.11` or `ghcr.io/org/image:tag`). |
| `unsupported_platform` | The base image isn't `linux/amd64`.                                                          |
| `image_pull_failed`    | Base image couldn't be pulled or resolved — bad reference, or the registry was unreachable.  |
| `image_unsafe`         | Image rejected for unsafe paths (tar / symlink / hardlink entries escaping the root).        |
| `image_too_large`      | Flattened image exceeds the requested `diskMib`; raise `diskMib`.                            |
| `step_failed`          | A build step exited non-zero. The message includes the failing step and its exit code.       |
| `boot_failed`          | Build VM failed to boot.                                                                     |
| `snapshot_failed`      | Snapshot couldn't be captured.                                                               |
| `start_cmd_failed`     | `startCmd` didn't launch successfully.                                                       |
| `ready_cmd_failed`     | `readyCmd` didn't exit `0` within 10 minutes.                                                |
| `dispatch_failed`      | The build host was unreachable when the build was dispatched.                                |
| `build_failed`         | Catch-all when no specific code applies.                                                     |

`Template.create` / `rebuild` can also be rejected **before a build starts** with a `RateLimitError` — `too_many_builds` (team's concurrent-build limit) or `too_many_templates` (team's template-count limit). These are not `BuildError` codes; see [Errors](/errors#ratelimiterror).

## Related

* [Create a template](/templates/create)
* [Errors](/errors)
