---
title: Deploy a folder to a machine
description: "Have Ysra put a whole folder, such as a built website or an app, onto a machine in one approved step, and go back if you need to."
new_in: "2.2"
---

**Deploying a folder** puts a whole folder — a built website, an app, files a
service reads — onto a [machine](overview.md) in one step, and keeps the
previous version beside it. Before you start, the machine must be reached
over **SSH** (a machine reached through `govc`, `kubectl` or another tool
can’t receive a folder) and be in [change mode](overview.md#modes). For one
file, see [Write a file](write-file.md).

## Steps

1. Ask in a thread:

    ```text
    › deploy the dist folder to /var/www/sites/shop on web-01
    ```

2. Read the card, titled **Deploy dist to /var/www/sites/shop on web-01?**

    | Part | Example |
    |---|---|
    | What and where | *dist → /var/www/sites/shop on web-01* |
    | Size | *12 files · 248 KB · replaces the current folder (11 files)*, or *new folder* |
    | **Files** | The full tree, with each file’s size; folders start closed above 30 files |
    | **Left out on purpose** | Files never sent, and why (below) |
    | Backup | *The current folder is kept as /var/www/sites/shop.ysra-bak.<time>.* |
    | **On**, **Why**, **Expect**, **Undo** | As on any [change card](overview.md#approvals). Undo reads *put the backup back*, or *delete the new folder* for a new one |

3. Choose **Run it** or **Skip** (in the terminal, answer **OK?**). Only you
   can answer; auto mode never does.

The thread records the result, and the machine’s list of what ran shows
`deploy → /var/www/sites/shop`:

```text
Deployed dist to /var/www/sites/shop on web-01: 12 files, 248 KB; the previous version is at /var/www/sites/shop.ysra-bak.20261007T091203.
```

## How the folder lands

| Step | What happens |
|---|---|
| 1. Pack | The folder is packed on the device and sent over SSH |
| 2. Unpack | Into a new folder beside the destination |
| 3. Check | Every file is checked against a list of checksums made before sending |
| 4. Swap | The current folder is renamed `<dest>.ysra-bak.<time>` (for example `shop.ysra-bak.20261006T115448`) and the new one takes its place |

If anything fails before the swap, the new folder is removed and the
destination is left as it was: *I couldn’t deploy to /var/www/sites/shop on
web-01; it’s as it was: …*

### Going back

There is no undo command. Move the backup folder into place on the machine,
or ask Ysra to; that is a change, so it asks first.

## Left out on purpose

These are never deployed, wherever they sit in the folder, and are listed on
the card so nothing is skipped silently. If the site really needs one, put it
on the machine yourself.

| Group | Files |
|---|---|
| Version control and dependencies | `.git`, `node_modules` |
| Environment files | `.env` and every `.env.*` |
| Keys and certificates | `*.pem`, `*.key`, `*.p12`, `*.pfx`, and `id_*` files other than `*.pub` |
| Credential stores (file or folder, any depth) | `.ssh`, `.gnupg`, `.kube`, `.docker`, `.netrc`, `.git-credentials`, `.mozilla`, `.password-store`, `.ysra`, `.npmrc`, `.pypirc`, paths such as `.config/git/credentials`, and the sign-in folders of hosting tools |
| System secrets | `shadow`, `sudoers` and similar |
| Not plain files | Symbolic links, and anything that isn’t a plain file or folder |

## Which approval kind it counts as

For [signed approvals](approvals.md), a deploy counts as **config**. A
destination holding SSH configuration counts as **access**; one holding
`passwd`, `shadow`, `group` or `sudoers` counts as **users**.

## If it doesn’t work

| Case | Ysra says |
|---|---|
| A system folder (`/`, `/etc`, `/usr`, `/var`, `/var/www`, `/home`, `/opt`, `/srv` and similar), or a path less than two levels deep | *I won’t replace /var/www: deploy into a folder of its own, e.g. /var/www/sites/<name>.* |
| A destination that holds secrets | *I don’t deploy into /root/.ssh: it holds secrets.* |
| A source over 200 MB | *I won’t deploy dist: it’s over 200 MB.* |
| A source with more than 20,000 files | *I won’t deploy dist: it has more than 20000 files.* |
| An empty source | *There’s nothing to deploy in dist.* |
| A source outside the folder Ysra works in | *… leads outside this folder; I deploy only from inside it.* |
| A destination that is a symbolic link | *… is a link (to …); deploy to the folder itself instead.* |
| A destination that is a file | *… is a file, not a folder, so I didn’t replace it.* |
| A machine reached through a command-line tool | *… is reached through govc; folders are deployed over SSH only.* |
| A look-only machine | *web-01 is in observe mode, so I only look there. Switching it to change mode is your call (`ysra machines mode web-01 change`).* |
| You chose **Skip** | *You didn’t approve that, so I didn’t deploy it.* Ysra doesn’t try again |

## Related

- [Deploy a site to your server](deploy-site.md) — from an empty folder to a page that answers.
- [Write a file on a machine](write-file.md) — one configuration file, such as the web server’s site file.
- [How machines work](overview.md) — modes and the change card.
