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

# Snapshot your app

> Install your app on one machine, snapshot it, and keep the snapshot fresh on every push to main.

Take a [snapshot](/guides/snapshots) of a machine with your app fully set up: repo cloned, dependencies installed, services running. Once it exists, anyone (or any script) can create a ready machine from it in one command, with the app already serving. Keep the snapshot refreshed on every push to main and it always reflects your latest code.

This is the base layer for [preview environments](/use-cases/preview-environments), disposable test machines, and warm agent sandboxes.

## 1. Set up the machine

Create a machine and install your app on it the way you would set up a fresh laptop:

```bash theme={"theme":"github-dark"}
boxd machine new myapp
boxd connect myapp
```

Inside the machine:

```bash theme={"theme":"github-dark"}
git clone https://github.com/you/myapp.git
cd myapp
npm ci                          # or pip install, cargo build, ...
sudo systemctl enable --now myapp   # start it under systemd, pm2, or docker compose
```

With [Git](/guides/integrations/connections#git) connected, the clone works against private repos on your private machines with nothing to configure. Run the app under `systemd`, `pm2`, or `docker compose`, so it also comes back after a reboot.

Point the machine's proxy at your app's port and check it serves:

```bash theme={"theme":"github-dark"}
boxd machine proxy set-port --vm myapp --port 3000
# open https://myapp.boxd.sh
```

Secrets your app needs belong in [env vars and secrets](/guides/env-secrets), which boxd injects into the machines in the var's scope. Values baked into the snapshot's disk end up in every machine created from it, so keep credentials out of the snapshot itself.

## 2. Snapshot it

```bash theme={"theme":"github-dark"}
boxd snapshots save myapp my-workspace
```

The capture includes memory and disk together, so a machine created from it resumes with the app already running. Nothing boots. Test it:

```bash theme={"theme":"github-dark"}
boxd machine new myapp2 --from-snapshot my-workspace
# open https://myapp2.boxd.sh: your app, already serving
boxd machine remove myapp2 -y
```

<Frame caption="Save a snapshot, then start a machine from it. Booted in 4ms.">
  <video autoPlay muted loop playsInline src="https://mintcdn.com/azin/toBfp1IaOCRwpFnS/videos/from-snapshot.mp4?fit=max&auto=format&n=toBfp1IaOCRwpFnS&q=85&s=8c1e5d7669b6845c362b612d8834c7a6" data-path="videos/from-snapshot.mp4" />
</Frame>

Saving again under the same name replaces the version, and the latest version is what new machines get. `my-workspace` therefore stays one name your scripts and teammates can rely on while the content moves forward. While a new version is saving, creating a machine from that name fails until the save is ready.

## 3. Refresh it on every push to main

Keep the snapshot current by re-syncing the machine and re-saving the snapshot whenever main changes. The recommended way to automate this is through the [TypeScript](/reference/typescript-sdk) or [Python](/reference/python-sdk) SDK, which reads a `BOXD_API_KEY` from the environment and handles authentication for you. The whole refresh is a few lines:

<Tabs>
  <Tab title="TypeScript">
    ```typescript refresh-snapshot.ts theme={"theme":"github-dark"}
    import { Boxd } from "@boxd-sh/sdk";

    const boxd = new Boxd();   // reads BOXD_API_KEY

    await boxd.machines.exec("myapp", {
      command: "cd ~/myapp && git pull && npm ci && sudo systemctl restart myapp",
    });
    await boxd.snapshots.create("myapp", "my-workspace");

    await boxd.close();
    ```
  </Tab>

  <Tab title="Python">
    ```python refresh_snapshot.py theme={"theme":"github-dark"}
    from boxd import Boxd

    with Boxd() as boxd:   # reads BOXD_API_KEY
        boxd.machines.exec(
            "myapp",
            "cd ~/myapp && git pull && npm ci && sudo systemctl restart myapp",
        )
        boxd.snapshots.create("myapp", "my-workspace")
    ```
  </Tab>
</Tabs>

Swap the sync command for whatever your stack needs (`pip install`, `cargo build`, `docker compose up -d --build`, a migration step). The `exec` also wakes the machine if it was hibernated, and the save requires it `running`, which it then is.

Run the script from anything that reacts to a push to main. Wiring it into GitHub Actions is one small job: run it on `push` to your default branch with `BOXD_API_KEY` stored as a repo secret. Mint the key once, without it touching your clipboard:

```bash theme={"theme":"github-dark"}
boxd auth keys create "refresh-snapshot" | gh secret set BOXD_API_KEY --repo you/myapp
```

The key is fenced to one org. See [API keys](/cli/authentication#api-keys).

<Tip>
  You can also run the script on a boxd machine, for example on a self-hosted runner or a small webhook listener living there. Inside a machine, `new Boxd()` authenticates automatically, so the key disappears entirely and the script above runs unchanged.
</Tip>

## 4. Create machines from it

From now on, a ready copy of your app is one command away:

```bash theme={"theme":"github-dark"}
boxd machine new myapp-pr-482 --from-snapshot my-workspace # a preview for a pull request
boxd machine new alice-dev --from-snapshot my-workspace    # a dev workspace for a teammate
boxd machine new agent-run-7 --from-snapshot my-workspace  # a warm sandbox for an agent
```

Each machine gets its own URL, SSH access, and disk, and starts from the latest version of the snapshot. [Preview environments](/use-cases/preview-environments) builds this into a per-PR workflow.

<Note>
  A [fork](/guides/fork) also copies a running machine, directly and in milliseconds, but it copies the machine as it is **right now**. A snapshot gives you a named starting point that stays the same while the source machine moves on, and that outlives the machine.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.