← Alle Playbooks
Playbook· setup

Memory backup before an update, so you do not cry over a schema migration bug

How to secure your agent memory, your Claude Code configs and your MCP server state before you update or migrate. With a concrete pg_dump command, a restore test and a retention strategy.

Updates are rarely the problem. Updates where something goes sideways are the problem. Back in April I had a Prisma migration that accidentally forced a new constraint onto our agent_observations table. Roughly 4,000 observations were dead. Luckily we had a pg_dump from two days earlier, otherwise the whole memory layer of the fleet would have been gone. Ever since, a backup before an update is mandatory, not a nice-to-have. Here is the routine I have run since then.

1. Get clear on what actually needs backing up

Memory is not just the database. It is several things together. The Postgres database with all the agent_* tables is the big chunk. Then the configs, so ~/.claude/settings.json, ~/.claude/mcp.json or .claude.json depending on your setup. Then the skills and sub-agents under ~/.claude/skills/ and ~/.claude/agents/. And if you host MCP servers yourself, their state as well (often Postgres or SQLite too).

If you only secure the DB and forget the .claude configs, in an emergency you restore into an environment where Claude has no idea which MCP servers exist. I did that once and spent two hours reconfiguring tools afterwards.

2. Which DB are we even talking about

Check where your memory really lives. In most setups I have seen it is Postgres, either locally or on a server. Look it up in the MCP config. In my case it is postgres://localhost:5433/your_app_db with the nex_* and agent_* tables in it.

If you use a memory-as-a-service solution (the hosted variant), the DB is not on your side. Then your backup job is an export API call or a hosting provider snapshot. Sort that out beforehand, not while the disaster is happening.

3. The pg_dump command that actually works

Do not just use pg_dump dbname > file.sql. That gets unwieldy fast with larger memory databases. Custom format with compression is better.

pg_dump \
  --host=localhost \
  --port=5433 \
  --username=postgres \
  --dbname=your_app_db \
  --format=custom \
  --compress=9 \
  --file=memory-backup-$(date +%Y-%m-%d-%H%M).dump

That gives you a compact binary file readable with pg_restore. For my 107 MB database that comes out at roughly 18 MB of backup. Compress 9 is slow, but for one step per day or per update it does not matter.

Optionally you can add --exclude-table='pg_*' if you want to leave out the system stuff, though custom format largely ignores it anyway.

4. Back up the configs separately

A tarball over the entire .claude directory. Small, fast, complete.

tar -czf claude-config-$(date +%Y-%m-%d).tar.gz \
  -C "$HOME" .claude

If you have secrets in the configs (API keys in mcp.json), take that seriously and do not drop the tarball into a public bucket. Encrypt it or keep it local. Classic anti-pattern: a backup script that pushes to S3 without anyone checking the bucket policy.

5. A test restore into a second DB

A backup without a restore test is not a backup. I learned that the hard way once. Do it now, once, and you know it works.

createdb -h localhost -p 5433 -U postgres memory_restore_test
pg_restore \
  --host=localhost --port=5433 --username=postgres \
  --dbname=memory_restore_test \
  --no-owner --no-privileges \
  memory-backup-2026-05-19-1430.dump

Then run a SELECT count(*) FROM agent_observations; on the test DB and compare it against the real one. If the numbers match, your backup is good. Then dropdb the test database.

You do this test once when setting things up, and after that again following every larger schema update. Not daily. It gets annoying otherwise.

6. Backup lifecycle, how many to keep

Three tiers that have worked well for me. Last 7 days, one per day. Then the last 4 weeks, one per week. Then the last 12 months, one per month.

With compress 9, at my database size that adds up to roughly 1 GB of backup volume in total. Irrelevant on a 500 GB server. Cheap on a Hetzner Storage Box.

A concrete cleanup script pattern (not copy-paste, adapt it to your structure):

# Keep the last 7 dailies, delete the rest
find ./backups/daily -name "memory-backup-*.dump" -mtime +7 -delete

7. Automate it with cron, but with a heads-up mail

Backups nobody checks are not backups. A cron entry that runs the dump every night at 3 and mails you the result.

0 3 * * * /usr/local/bin/memory-backup.sh 2>&1 | mail -s "Memory Backup $(hostname)" you@example.com

If you get no mail for a week, you know something is broken. But if the mail says "OK" every single day, you will tune it out after three weeks and still not notice. Better: mail only on failure. Or a healthcheck service that gets pinged when the script runs and alerts you when it has heard nothing for 30 hours.

8. A fresh pre-update dump before every update

This is the actual point of this playbook. Before every migration run, before every Prisma db push, before every migrate deploy, take a dump and name it clearly.

pg_dump ... --file=memory-pre-update-$(date +%Y-%m-%d-%H%M)-VOR-PRISMA-MIGRATE.dump

Sounds like overkill, but it is discipline. If the migration works out, you delete the dump a week later. If it does not, you have the right state from 10 minutes ago instead of the one from last night.

On my side this runs as a pre-commit hook on the Prisma migrations folder. When a schema file changes, git asks whether I want a backup first. 80 percent yes, 20 percent no (dev DB, who cares).

9. The memory-as-a-service special case

If you use a hosted memory solution (through a cloud MCP provider, say), the backup behaviour is different. Check three things.

Does the provider take automatic snapshots, and if so how often. For many it is every 6 or 24 hours, which can be too little in the face of a schema bug.

Is there an export API. You do not want to be dependent. Check whether there is an /export route that hands you your data as JSON or SQL.

What happens if the provider goes bust. Sounds paranoid, but with smaller MCP providers it is real. Pull an export at least once a week and store it locally.

10. A restore drill once per quarter

Last step, for the long run. Once per quarter you take your newest backup, restore it into a test DB, point Claude Code at it with a test config, and check whether it reads memory. It is no fun, but if it takes a third of an hour and you do it once a quarter, you are immune to the classics.

What you want to test in the process. Does the restore go through. Does Claude see the observations and decisions. Do the cross-agent recalls still come through (permissions, indexes). Does a search on an old tag work.

If any of that fails, you know it now instead of in an emergency.

If you want to keep memory clean for the long haul after that, take a look at Repair memory drift and Using memory portably. Backup is the emergency layer, hygiene and portability are the daily work.