# swb hold

Holds an installed app at a version: the channel its subscription follows
moves on without it until the hold is released.

## Synopsis

```
usage: swb hold <app> <version> --env <env> [--json]
```

## Arguments and flags

| Argument or flag | Takes | Default |
|---|---|---|
| `<app>` | The app's **id** — the app whose install is held. Required. | — |
| `<version>` | The **version** to hold, as the build published it: `1.8.2`. Its release tag, `v1.8.2`, names the same version and is read as it. An app with no repository must have had that version uploaded; an app built from a repository's version is taken as given. Required. | — |
| `--env` | An environment's **name or id**; a name is matched first. Required. | — |
| `--json` | Nothing. Prints the subscription as the API answered it instead of the one-line summary. | off |
| `--help`, `-h` | Prints the command's help and exits. | off |

## What it does

Calls `Mutation.holdVersion` for the app's install in that environment with a
fresh client token, so a repeated call is one hold rather than two. The hold is
recorded on the install's subscription: the version, who held it and when.
Holding the version already held changes nothing and still names who held it
first; holding another version replaces the hold. An install that has never
had a subscription gets one from its first hold, on `manual`, following
`stable` in a production environment and `beta` in any other, as the
environment's class says.

A hold shows on the install and in the app's
[history](/command-line/history), as a `hold-set` entry, and deploys the held
version: within a minute the install has a deploy of it, started by `HOLD`
and requested by you, as its subscription's policy and gate say — offered
under `manual`, to run with [`swb run-deploy`](/command-line/run-deploy),
deployed at once under `auto`, and waiting for an approver other than you
under a gate. It replaces the deploy the install was offered and nobody ran.
No deploy is written where the install already runs the version with nothing
waiting, or already has a deploy of it that has not ended. While the hold
stands, the channel's new versions pass the install by,
[`swb deploy`](/command-line/deploy) is refused, and only the hold's own
deploy runs.

In an environment of the production class, a hold returns to a version that
environment has already deployed successfully — the install's own deploys
there say so — which is what an undo is: going back to what ran there passes
no gate the first run did not pass. A version that never ran there is
refused, as a move of `stable` outside a release is, and a hold does not yet
admit a version an approved release carries. Every other environment holds
any published version.

## What it prints

```
crew-signout in prod: held at 7 by Maria Ruiz at 2026-10-07 13:00, following stable
```

— the app, the environment, the version held, who held it (the name their
sign-in account carries, as Switchboard last read it, or `Unnamed person`
where it carries none, never their sign-in id, and the product they acted
through where they acted through one), when, and the channel the subscription follows.

`--json` prints the subscription as the API answered it: `installId`,
`appId`, `environmentId`, `channel`, `policy`, `held`, `heldBy` (`kind`, `id`,
`via`, `name`) and `heldAt`.

## The operation and the permission

`Mutation.holdVersion`. The caller needs `swb.deploys.run` on the tenant.
`swb hold` also reads `Query.me` once for the tenant and `Query.tenant` to
turn the `--env` name into an id.

## Refusals and exit status

Exit status is 0 once the hold is recorded, and 1 on every refusal below.

| Refusal | When |
|---|---|
| `swb hold takes <app> <version>` | An argument is missing. |
| `swb hold needs --env <env>` | `--env` was not given. |
| `no environment named "<env>" in tenant <tenant> (have: dev, staging, prod)` | No environment of the tenant has that name or id. |
| `not signed in or token expired — run swb login` | There is no usable credential. |
| `NotFound: Install <app>#<env> not found` | The tenant has not installed the app in that environment. |
| `NotFound: Version <app>@<version> not found` | An app with no repository has had no upload of that version. |
| `ValidationFailed: …` naming `class` | An environment that records no class. |
| `Refused: <app> <version> has never been deployed in <env> …` (`guard: release-only`) | An environment of the production class that has never deployed that version, which no approved release carries. Where the environment's older deploys were not read, the refusal says so instead. |
| `NotAuthorized: …` | The caller lacks `swb.deploys.run`. |
| `Conflict: …` | Another hold or release of the install landed first; the refusal names the hold that stands. |

## Example

```console
$ swb hold crew-signout 7 --env prod
crew-signout in prod: held at 7 by Maria Ruiz at 2026-10-07 13:00, following stable
```

Release it with [`swb release-hold`](/command-line/release-hold).
