Over time, my Claude Code setup stops being default. I tune the settings, write a
status line script, add hooks, drop in a few skills, and grow a global CLAUDE.md
of habits. None of that is in the app — it's a pile of files in ~/.claude. Lose
that folder and I don't lose Claude Code; I lose my Claude Code. This post is
about backing it up: why it's worth doing, which files actually matter, and the one
file you must never copy anywhere.
Why back up at all
The config lives in one folder on one machine. That's fragile in a few ways:
- New machine, from scratch. Set up a new laptop and you start with a blank
~/.claude. Without a backup, you're rebuilding every setting, hook, and script from memory. - Keeping two machines in sync. Work laptop, home desktop — you want the same status line and the same habits on both. A backup is the thing you sync from.
- Recovering a bad edit. You tweak
settings.json, something breaks, and you can't remember what it looked like before. If the backup is in git, the old version is onegit diffaway. - History and review. Once your config is in a repo, every change is a commit. You can see when you added a hook and why, and roll it back if it misbehaves.
The fix is small: copy the hand-authored files somewhere safe — I use a private git
repo — and commit. The trick is knowing which files, because ~/.claude is mostly
stuff you should leave behind.
What actually needs backing up
Only a handful of things in ~/.claude are yours in the sense that matters — you
wrote them, and you'd have to rewrite them. Here's what my backup script copies, and
what each one is:
CLAUDE.md— my global memory: writing style, git safety rules, commit format. The instructions Claude reads in every project.settings.json— the main config: permissions, hooks, the status line command, model and theme choices, enabled plugins. The heart of the setup.statusline.sh— my custom status line script (the one from the earlier post).settings.jsonpoints at it, so the two travel together.file-suggestion.sh— a helper scriptsettings.jsoncalls for file suggestions. Another "settings points at a script" pair.hooks/— the scripts my hooks run (like the "done" sound gatekeeper). The hook config insettings.jsonis useless without these files.skills/— my custom skills. Hand-built, so worth keeping.commands/— custom slash commands, if you have any. Same story: yours, rewrite-if-lost.
In my backup script (rsync.sh), that's a list of plain copies into a repo folder:
REPO=~/workspace/config
rsync -av --mkpath ~/.claude/CLAUDE.md "$REPO/.claude/CLAUDE.md"
rsync -av --mkpath ~/.claude/settings.json "$REPO/.claude/settings.json"
rsync -av --mkpath ~/.claude/statusline.sh "$REPO/.claude/statusline.sh"
rsync -av --mkpath ~/.claude/file-suggestion.sh "$REPO/.claude/file-suggestion.sh"
rsync -av --mkpath ~/.claude/hooks/ "$REPO/.claude/hooks/"
rsync -av --mkpath ~/.claude/skills/ "$REPO/.claude/skills/"
rsync -av copies recursively and preserves permissions (so statusline.sh stays
executable); --mkpath creates the destination folders if they don't exist. After
the copy, a git commit in the repo captures the change.
The per-project files, too
Config isn't only global. Each project can have its own CLAUDE.md (shared) and
CLAUDE.local.md (personal), and its own .env files. Those are worth backing up
in the same pass. Since the pattern repeats across many repos, I wrote two small
helpers instead of copy-pasting:
# Copy CLAUDE.md and CLAUDE.local.md from a project into the backup repo.
sync_claude() {
local src="$1" dest="$2" f
shopt -s nullglob
for f in "$src"/CLAUDE.md "$src"/CLAUDE.local.md; do
rsync -av --mkpath "$f" "$dest/$(basename "$f")"
done
shopt -u nullglob
}
# Copy every .env / .*.env file from a project into the backup repo.
sync_envs() {
local src="$1" dest="$2" f
shopt -s nullglob
for f in "$src"/.env "$src"/.*.env; do
rsync -av --mkpath "$f" "$dest/$(basename "$f")"
done
shopt -u nullglob
}
Then one line per project: sync_claude ~/workspace/some/project "$REPO/.../project".
nullglob makes the loop skip cleanly when a project has no such file, instead of
trying to copy a filename that doesn't exist.
What to leave out — and why
Most of ~/.claude is not worth backing up, and copying it would make the backup
big, noisy, and slow. Skip these:
projects/— per-project session transcripts and the notes Claude writes to itself. Large, machine-local, and regenerated as you work. This is the bulk of the folder.sessions/,shell-snapshots/,history.jsonl,file-history/— session and history state. Local runtime, not config.cache/,paste-cache/,stats-cache.json,downloads/,daemon/,ide/,jobs/,tasks/— caches and runtime scratch. All regenerated.plugins/— installed plugins. They re-install;settings.jsonalready records which ones you enabled.backups/,settings.json.bak,.last-*— the app's own local backups and bookkeeping.
The rule of thumb: back up what you wrote by hand; skip what the app generates. If losing a file would only cost you a re-download or a regenerated cache, it doesn't belong in the backup.
The one file you must never back up
There's a single file in ~/.claude that is both tempting to grab (it's small) and
dangerous to copy:
~/.claude/.credentials.json
This is your login token. Copy it into a git repo and you've put a live key to your account into your history — where it can leak, sync to a remote, or end up in a clone. Notice it's absent from every line of my backup script. That's on purpose. You never need it in a backup: on a new machine you just log in once and Claude Code writes a fresh one.
The broader rule: secrets go only in a private store, and live tokens don't go in
at all. My backup repo is private, which is the only reason it can hold .env
files at all — but even in a private repo, the account credential stays out. If your
backup could ever become public or shared, keep every secret out of it.
Restoring on a new machine
Because the backup is just files in a repo, restoring is the copy in reverse: clone
the repo on the new machine and rsync the .claude folder back into place.
git clone <your-private-config-repo> ~/workspace/config
rsync -av ~/workspace/config/.claude/ ~/.claude/
# then log in once to create a fresh ~/.claude/.credentials.json
Settings, status line, hooks, and skills land exactly where they were. You log in once, and you're back to your Claude Code — not the default one.
A checklist to steal
- Back up the hand-authored files:
CLAUDE.md,settings.json,statusline.sh,file-suggestion.sh,hooks/,skills/, andcommands/. - Back up per-project
CLAUDE.md/CLAUDE.local.mdand.envfiles if you want a full restore. - Skip the generated stuff:
projects/,sessions/, caches,plugins/, and the app's ownbackups/. - Never copy
~/.claude/.credentials.json— log in fresh instead. - Keep the backup private, and put it in git so every change is a reviewable commit.
Your Claude Code setup is a small, valuable thing you build up quietly over months.
A dozen lines of rsync and a git repo mean you never have to build it twice.
Comments
Be the first to comment.