# Configure a machine
URL: https://metorial.com/docs/build/sandboxes/machines

Set the size, region, environment, and startup commands of a sandbox machine.

---

Every machine is configured when you create it, and most settings can change later. This page covers size, region, the runtime (what runs when the machine boots), and how updates apply to a running machine.

<PageIntro>
  <Learn>
    * How to size a machine
    * How to set environment variables and startup commands
    * What happens when you update a running machine
  </Learn>

  <Reading title="Before you start">
    * [Run your first machine](/docs/build/sandboxes/quickstart)
  </Reading>
</PageIntro>

## Size [#size]

Pick a size in one of two ways:

* Use a spec, which is a predefined size. `specs list` shows each spec's memory, CPUs, regions, and whether your plan allows it (`available`). Pass `--spec-identifier`.
* Set custom memory and CPUs in steps of 0.5. Pass `--memory-gib` and `--cpus` together.

```bash
metorial-admin sandbox specs list
metorial-admin sandbox machines create --region iad1 --image-id $IMAGE --memory-gib 4 --cpus 2
```

If you set neither, the machine gets the default size.

## Region [#region]

Every machine runs in one region. Its image must be available there, and its disks must live there. List regions with `metorial-admin sandbox regions list` and filter machines by region with `machines list --region iad1`.

## Runtime [#runtime]

The runtime decides what runs when the machine boots. All fields are optional, and fields you leave out use the image's defaults.

| Field         | What it does                                                             |
| ------------- | ------------------------------------------------------------------------ |
| `setup`       | Commands that run before the entrypoint starts                           |
| `entrypoint`  | The main process of the machine                                          |
| `cmd`         | Arguments passed to the entrypoint                                       |
| `env`         | Environment variables for the entrypoint                                 |
| `workdir`     | Working directory of the entrypoint                                      |
| `user`        | User the entrypoint runs as                                              |
| `stop_signal` | Signal the entrypoint receives when the machine stops, such as `SIGTERM` |

`entrypoint_wait_seconds` sets how long startup waits for the entrypoint before the machine counts as running. The default is `0`.

This machine installs dependencies, then runs a web server on port 3000:

```bash
metorial-admin sandbox machines create \
  --region iad1 \
  --image-id $IMAGE \
  --runtime '{
    "setup": ["npm ci --prefix /app"],
    "entrypoint": ["node", "/app/server.js"],
    "env": { "PORT": "3000", "NODE_ENV": "production" },
    "workdir": "/app"
  }'
```

Use `--runtime-file runtime.json` to keep larger configs in a file.

<CodeBlockTabs defaultValue="TypeScript" groupId="language" mode="code">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="TypeScript">
      TypeScript
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="TypeScript">
    ```typescript
    let machine = await metorial.sandbox.machines.create({
      region: 'iad1',
      imageId: 'sbi_your_image_id',
      memoryGib: 4,
      cpus: 2,
      runtime: {
        setup: ['npm ci --prefix /app'],
        entrypoint: ['node', '/app/server.js'],
        env: { PORT: '3000', NODE_ENV: 'production' },
        workdir: '/app'
      }
    });
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    ```python
    machine = metorial.sandbox.machines.create(
        region="iad1",
        image_id="sbi_your_image_id",
        memory_gib=4,
        cpus=2,
        runtime={
            "setup": ["npm ci --prefix /app"],
            "entrypoint": ["node", "/app/server.js"],
            "env": {"PORT": "3000", "NODE_ENV": "production"},
            "workdir": "/app",
        },
    )
    ```
  </CodeBlockTab>
</CodeBlockTabs>

<Tip>
  Install packages in a [custom image](/docs/build/sandboxes/custom-images) instead of in `setup`. Machines boot faster when the image already has everything.
</Tip>

## Names and metadata [#names-and-metadata]

Give machines a `name` and attach your own `metadata`, such as the user or task a machine belongs to. Metorial stores metadata but never reads it.

```bash
metorial-admin sandbox machines update $MACHINE --metadata '{"user_id": "usr_42", "task": "nightly-report"}'
metorial-admin sandbox machines list --search nightly --state running
```

`machines list` filters by `--state`, `--image-id`, `--region`, and `--search` (name, slug, or ID). Deleted machines only show up with `--status deleted`.

## Update a machine [#update-a-machine]

`machines update` changes a machine in place. Names, metadata, [lifecycle policies](/docs/build/sandboxes/lifecycle), [firewalls](/docs/build/sandboxes/networking#control-outbound-traffic), and public ports apply immediately.

Changes to the size, runtime, or [mounts](/docs/build/sandboxes/disks) need a restart. Until it happens, the machine reports `restart_required: true`. Metorial restarts a running machine on its own and applies the change to a paused machine by hibernating it. To apply it right away, restart the machine yourself:

```bash
metorial-admin sandbox machines update $MACHINE --memory-gib 8 --cpus 4
metorial-admin sandbox machines restart $MACHINE
```

A restart boots the machine on a fresh instance. Files on the root disk and attached disks stay; running processes and memory don't.