---
title: "Workers"
description: "Provisioning, rotating and retiring worker credentials."
url: "https://saved.sh/docs/cli/workers"
---

A worker is a **credential**, not a machine. These commands manage the credential; installing
and running the process is [separate](/docs/workers/install).

## Provisioning [#provisioning]

```bash
sctl worker provision prod-worker-1
```

```
Provisioned worker "prod-worker-1" (0f2c9a1e-...).

  Key (copy now, not shown again):
  sk_live_...
```

<Callout type="error">
  The key is shown **once** and is not recoverable. It goes into that machine's `config.yaml`
  as `token`. If you lose it, [rotate](#rotating) rather than deleting the worker.
</Callout>

Names are 1 to 100 characters and are for you. The **ID** is what backups reference.

## Listing [#listing]

```bash
sctl worker list
```

```
NAME            ID              CREATED               UPDATED
prod-worker-1   0f2c9a1e-...    2026-08-08T09:14:02Z  2026-08-08T09:14:02Z
```

This is where you get the worker ID that `sctl backup configure --worker` needs.

```bash
WORKER_ID=$(sctl worker list | awk '$1 == "prod-worker-1" { print $2 }')
sctl backup configure "$BACKUP_ID" --worker "$WORKER_ID"
```

<Callout>
  The dashboard additionally shows how many processes are polling and when each was last seen.
  Read those as "connected is trustworthy, disconnected lags by minutes": poller records expire
  on a TTL, so a worker that died thirty seconds ago can still look present.
</Callout>

## Rotating [#rotating]

```bash
sctl worker rotate <worker-id>
```

```
Rotated worker "prod-worker-1" (0f2c9a1e-...).

  New key (copy now, not shown again):
  sk_live_...
```

Rotation keeps the **worker ID**, so every backup assigned to it keeps working once the new
key is deployed. This is the answer to almost everything: a leaked key, a decommissioned host,
an employee who had access to the config file, or ordinary hygiene.

The order that minimises the gap:

1. `sctl worker rotate <worker-id>`
2. Write the new key into that machine's `config.yaml`
3. Restart the worker

<Callout type="warn">
  **The old key is revoked the moment the new one is issued.** Any process still holding it
  stops being able to poll, so expect a short gap. A run already in flight is retried when the
  worker returns, because the run belongs to the queue rather than to the connection.
</Callout>

## Deleting [#deleting]

```bash
sctl worker delete <worker-id>
```

Deletion revokes the key permanently and removes the worker. Backups assigned to it are left
with nowhere to run: their scheduled runs queue on a task queue nothing polls.

|                  | `rotate`     | `delete`            |
| ---------------- | ------------ | ------------------- |
| Worker ID        | Unchanged    | Gone                |
| Old key          | Revoked      | Revoked             |
| New key          | Printed once | There is none       |
| Assigned backups | Keep working | Have nowhere to run |

Reassign or pause those backups before deleting the worker they point at.

## What the key can do [#what-the-key-can-do]

Two permissions: `artifacts:upload` and `artifacts:confirm`. It cannot read backup definitions,
list artifacts, download anything, or manage workers, including itself.

That narrowness is why a worker is safe to run on a machine you would not trust with an API
key. The real risk on that host is the **config file**, which holds your source credentials.
Protect the file, not just the key.

## Limits [#limits]

| Plan  | Workers per workspace |
| ----- | --------------------- |
| Trial | 1                     |
| Paid  | 10                    |

## Next [#next]

<Cards>
  <Card href="/docs/workers/install" title="Install the worker" description="Getting the process running on a host." />

  <Card href="/docs/workers/configuration" title="Worker configuration" description="Where the key and the source credentials go." />

  <Card href="/docs/workers/registration" title="Registration" description="The same flow, in depth." />
</Cards>
