When a registry takes its first backup, sloop makes it an age keypair. Every backup that registry takes from then on is encrypted to it — and the two halves of that pair live in completely different places, for completely different reasons.
The asymmetry is the point
A symmetric key would mean the secret has to be present to write an encrypted backup — so a nightly job would need it unlocked, sitting somewhere a scheduler can reach, at three in the morning, unattended. That is the thing worth avoiding, and splitting the pair is what avoids it.
So a scheduled backup holds nothing you would mind it holding, and the one thing worth protecting is read by exactly one command. That is the design, and everything below is a consequence of it.
The first backup will not run until you have a copy
A key that exists only inside one machine is not a backup strategy — it is a machine you cannot afford to lose. So sloop says this once, hard, and refuses rather than warning:
$ sloop backup shop this registry has a new backup key age1t6mzq0xv9k2wr5ldh8nj3cp7yfs4ueg0a2xk9msv4rzq3ltdn6shqw8cjp backups from here on are encrypted to it. The private half is on this machine and nowhere else, so if this machine is lost, every one of those backups is unreadable — there is no recovery, no reset and nobody to ask. `sloop key export > backup-key.txt` writes it out. Keep that somewhere else.error: the backup key has not been copied anywhere yet, and there is no terminal to ask at hint: run `sloop key export` once, then this run will go through On a terminal it asks and will take no for an answer — declining explicitly is a decision, and it only has to be made once. With no terminal to ask at, as above, it exits 2 and names the command that settles it. Nothing was dumped, nothing was written.
Exporting it
$ sloop key exporta new backup key for /home/you/projects/acme-api/.sloop public age1t6mzq0xv9k2wr5ldh8nj3cp7yfs4ueg0a2xk9msv4rzq3ltdn6shqw8cjp private the OS keyring, and on standard output below keep that line somewhere sloop cannot reach — a password manager, a safe. Every encrypted backup this registry takes needs it, and nothing else can replace it. AGE-SECRET-KEY-1K9XW3MT25G5TU6LTSN07M55JPT9Y0T24MDNQZ2DXW202RULF43W44CQ The private key goes to standard output, deliberately, so that sloop key export > backup-key.txt is the whole of writing it down and the shell decides where it lands. Everything else on that block — the heading, the public key, the warning — goes to standard error, so the redirect captures the key and nothing else.
Running it again does not make a second key. The first word is the whole difference — a new backup key on the run that created one, the backup key every time after:
$ sloop key exportthe backup key for /home/you/projects/acme-api/.sloop public age1t6mzq0xv9k2wr5ldh8nj3cp7yfs4ueg0a2xk9msv4rzq3ltdn6shqw8cjp private the OS keyring, and on standard output below …Moving to another machine
This is the whole reason export and import exist, and it is worth walking through in order — because the step in the middle is the one that surprises people.
# on the machine that has the backups$ sloop backup shopshop postgres://app@127.0.0.1:5444/shop✓ Connected postgres 17.9, 2 tables, 10601 rows✓ Dumped 2 tables 67.6 kB, encrypted✓ Checked 42958e81e612 backed up to /home/you/projects/acme-api/.sloop/backups/postgres/shop/20260919T142852Z 66.0 KiB in 0.3s, sha256 42958e81e612 Copy that backups directory to the new machine — any way you like, it is ordinary files — into the registry there. sloop finds it immediately and reads it perfectly:
# on the new machine, after copying the backups directory across$ sloop backups listprojectshop postgres · 1 backup, 66.0 KiB 2026-09-19 20:28:52 +06:00 66.0 KiB, encrypted · 10601 rows 1 backup, 66.0 KiB · sizes checked, --check hashes themSize, timestamp, row count, all of it. That is the manifest talking, which is plain JSON and not encrypted. The dump beside it is another matter:
$ sloop restore shop --confirm shoprestoring /home/you/projects/acme-api/.sloop/backups/postgres/shop/20260919T142852Z taken 2026-09-19 20:28:52 +06:00 (2026-09-19T14:28:52Z) 66.0 KiB of postgres 17.9, encrypted, 10601 rows, sha256 42958e81e612 into shop — postgres 17.9 it is emptyerror: that backup is encrypted to age1t6mzq0xv9k2wr5ldh8nj3cp7yfs4ueg0a2xk9msv4rzq3ltdn6shqw8cjp and this registry has no key hint: `sloop key import` takes the key exported from the machine that made itIt names the public key the backup was encrypted to, so you can tell which key you are looking for rather than guessing. This is what losing the key looks like from the inside: a listing that reads perfectly and a dump that opens for nobody.
$ sloop key import < backup-key.txtimported age1t6mzq0xv9k2wr5ldh8nj3cp7yfs4ueg0a2xk9msv4rzq3ltdn6shqw8cjp kept in the OS keyring, and backups under /home/you/projects/acme-api/.sloop are encrypted to it from now on$ sloop restore shop --confirm shoprestoring /home/you/projects/acme-api/.sloop/backups/postgres/shop/20260919T142852Z taken 2026-09-19 20:28:52 +06:00 (2026-09-19T14:28:52Z) 66.0 KiB of postgres 17.9, encrypted, 10601 rows, sha256 42958e81e612 into shop — postgres 17.9 it is empty loaded in 0.1s checking it against the counts the manifest recorded✓ Verified exact count(*) on both sides verifying — exact count(*) on both sides public.customers 1284 → 1284 public.orders 9317 → 9317 2 of 2 tables matchedNothing about the backup changed between step 3 and step 5. The only difference is the Secret Service.
One key per registry, and sloop keeps it that way
Importing the key that is already there is a no-op, and it says so rather than pretending to work:
$ sloop key import < backup-key.txtalready the key here age1t6mzq0xv9k2wr5ldh8nj3cp7yfs4ueg0a2xk9msv4rzq3ltdn6shqw8cjpImporting a different key into a registry that already has one is refused. Accepting it would silently make every backup already taken unreadable — the registry would encrypt new ones to the new key and have nothing left that opens the old ones:
$ sloop key import < a-different-key.txterror: this registry is already encrypting to age1t6mzq0xv9k2wr5ldh8nj3cp7yfs4ueg0a2xk9msv4rzq3ltdn6shqw8cjp, and that is a different key hint: every backup already taken can only be read with the key it was written for. To move to a new key, take the `[encryption]` block out of the registry by hand first — and keep the old key, or those backups are gone The way out is deliberately manual, because it should be: take the [encryption] block out of the registry by hand, keep the old key, and let sloop make or take a new one. A flag for this would be a flag whose worst case is losing every backup you have, and --force is not offered here.
$ sloop key import < notes.txterror: that is not an age private key: invalid Bech32 encoding hint: it is the `AGE-SECRET-KEY-1…` line that `sloop key export` printedWhat you lose, and to what
Two different losses, and the page is only worth reading if you leave able to tell them apart.
Losing the machine
Nothing, if you exported the key. The backups are ordinary files — copy them wherever they need to go. A new machine, sloop key import, and sloop restore works exactly as it did. That is steps 1 to 5 above, and it is the case sloop is built for.
Losing the key
Every backup it ever encrypted. Not damaged, not partially readable — the dumps are age ciphertext and nothing opens them. sloop cannot help, there is no recovery path, and there is nobody to ask: the private half was never anywhere but that one machine's keyring, which is the property that made the scheduled backup safe in the first place.
Which is why the refusal at the top of this page exists, why it is a refusal and not a warning, and why it fires before the first encrypted backup rather than after it.
The backups page is what those encrypted files are and how they are taken, pruned and put back. Every flag both pages mention is on the command reference.