# Fork a running VM to run work in parallel

> Set up one sandbox, fork it into live copies with the setup done, run a different job in each, collect the results, and delete them all, with what it costs.

URL: https://prized.dev/docs/sandboxes-fork-parallel

Cloning a repo and installing its dependencies is often the slow part of a job. Do it once in one sandbox, then fork it: each copy starts with the parent's disk, memory and running processes. A fork does not make one job faster; it runs different jobs at once from one setup, such as a test suite on three Node versions.

The steps use the `prized` CLI (v0.21.0 or later), signed in or with `PRIZED_API_KEY` set ([CLI](https://prized.dev/docs/cli#sandboxes)).

## 1. Set it up once [#1-set-it-up-once]

```bash
ID=$(prized sandbox create --vcpu 2 --memory 2 --max-runtime 1h)
prized sandbox exec $ID --timeout 10m -- "git clone --depth 1 https://github.com/expressjs/express && cd express && npm install"
prized sandbox exec $ID --timeout 10m -- 'for v in 20 22 24; do npm install --prefix ~/node$v node@$v; done'
```

The last command puts one Node version per copy in your home, since there is no sudo. Copies keep the parent's shape, and a small shape fits more of them.

## 2. Fork it [#2-fork-it]

```bash
prized sandbox fork $ID --count 3 > copies.txt
```

This writes the copies' ids to `copies.txt` once each is running. The [free credit](#on-the-free-credit) allows a parent and 3 copies at once; a top-up or a plan allows more. Copies start on the parent's machine, so one fork makes at most:

| Shape                | Copies |
| -------------------- | ------ |
| 1 vCPU               | 31     |
| 2 vCPU               | 15     |
| 4 vCPU (the default) | 7      |
| 8 vCPU               | 3      |

More memory or disk, or a busy machine, fits fewer, and every copy counts against the workspace's [quotas](https://prized.dev/docs/limits#sandboxes). A fork that does not fit makes nothing and answers `409 fork_capacity` with `fits`, how many fit now (the CLI prints it): fork that many, or set up a new sandbox and fork that ([Fork](https://prized.dev/docs/sandboxes#fork)).

## 3. Run a different job in each [#3-run-a-different-job-in-each]

```bash
set -- 20 22 24
for C in $(cat copies.txt); do
  v=$1; shift
  (prized sandbox exec $C --cwd express -- "PATH=~/node$v/node_modules/.bin:\$PATH npm test" > node$v.log 2>&1; echo "node ${v}: exit $?") &
done
wait
# node 22: exit 0
# node 20: exit 0
```

`set --` lists the versions in the order of the copies, and each copy runs the whole suite on its own. To split one long suite instead, give each copy a shard, such as `npx vitest run --shard=2/3`.

## 4. Collect the results [#4-collect-the-results]

Each job's output is in its log on your machine, `node20.log` and the others, and its exit code in the loop's output. A file a job writes stays in its copy until you copy it out. For a suite that writes a JUnit report to `report.xml`:

```bash
prized sandbox cp $(head -1 copies.txt):express/report.xml report-node20.xml
```

## 5. Delete the parent and the copies [#5-delete-the-parent-and-the-copies]

```bash
prized sandbox rm $ID $(cat copies.txt)
```

Copies are ordinary sandboxes, billed like any other, so deleting the parent leaves them running. Each is deleted at its parent's deletion time at the latest, here an hour after the create.

## Over the API [#over-the-api]

The fork is `POST /api/v1/sandboxes/{id}/fork` with `{"count": 3}` ([Sandbox API: Fork](https://prized.dev/docs/sandboxes-api#fork)). It answers with the copies, each `starting`; read each until `running`, then send a harmless `true` to its own `toolboxBase` until it answers `200`, and only then the real job. Retry only that `true`: after a `502` a command may have run ([The edge](https://prized.dev/docs/sandboxes-api#the-edge)).

## What it costs [#what-it-costs]

Each copy bills per second at its own shape. A parent and 3 copies of 2 vCPU and 2 GB cost $0.424 an hour together, so 10 minutes of all four is $0.07 ([Billing: Sandboxes](https://prized.dev/docs/billing#sandboxes)).

## On the free credit [#on-the-free-credit]

Until the workspace has paid in, it runs 4 sandboxes at once with 8 vCPU in total, each for up to 60 minutes: a parent and 3 copies of 2 vCPU. A fork past a limit makes nothing and answers `429 sandbox_quota_exceeded` with `admitted`, how many copies would have fit. A top-up or a plan lifts this to the full quotas ([Free credit limits](https://prized.dev/docs/sandboxes#free-tier)).
