Syncing Claude Code Across Multiple Machines
I use Claude Code daily on two machines — a desktop workstation in my home office and a ThinkPad laptop. It’s a fantastic CLI-based AI coding assistant, but it has a gap: no built-in way to keep your configuration, custom commands, and project context in sync across machines.
After one too many times of building a great custom skill on one machine and having to manually copy it to the other, I decided to fix this properly. Here’s how I set up seamless multi-machine sync using tools I already had: a Synology NAS, symlinks, and Syncthing.
The Problem#
Claude Code stores everything — skills, custom commands, plugins, settings, API keys, and per-project memory — in ~/.claude/. When you work on two machines, you quickly run into:
- Custom skills built on one machine that don’t exist on the other
- API keys drifting out of sync between
.bashrcfiles - Project-specific Claude memory lost when you switch machines
- Settings changes applied on one machine and forgotten on the other
The Key Insight#
Not everything in ~/.claude/ should be synced the same way. The directory contains fundamentally different types of data:
~/.claude/
├── settings.json ← Should be shared
├── commands/ ← Should be shared
├── skills/ ← Should be shared
├── plugins/ ← Should be shared
├── projects/ ← Should be shared
├── .credentials.json ← Must stay local
├── sessions/ ← Must stay local
├── cache/ ← Must stay local
├── history.jsonl ← Must stay local
└── ...Settings and configuration need to be identical everywhere. Project files need fast local I/O. Session state must stay machine-local. This naturally splits into three sync strategies.
Layer 1: NAS + Symlinks for Settings#
The simplest approach for shared config: store the files on a network drive and symlink to them.
I have a Synology NAS with a dedicated SMB share called ClaudeCode, mounted at /mnt/claudecode-nas on both machines via /etc/fstab:
//192.168.1.222/ClaudeCode /mnt/claudecode-nas cifs credentials=/etc/smb-credentials-claudecode,uid=1000,gid=1000,iocharset=utf8,vers=3.0,_netdev 0 0Then on each machine, ~/.claude/ contains symlinks pointing to the NAS:
~/.claude/settings.json -> /mnt/claudecode-nas/settings.json
~/.claude/commands/ -> /mnt/claudecode-nas/commands/
~/.claude/skills/ -> /mnt/claudecode-nas/skills/
~/.claude/plugins/ -> /mnt/claudecode-nas/plugins/
~/.claude/projects/ -> /mnt/claudecode-nas/projects/Everything else (sessions, caches, credentials, history) stays local.
When Claude Code reads ~/.claude/settings.json, it follows the symlink to the NAS. Any change is instantly visible on all machines. No sync daemon, no conflict resolution, no polling — it’s just a file on a share.
API Keys#
API keys were previously hardcoded in ~/.bashrc on each machine. Now they live in a single shared file on the NAS:
# /mnt/claudecode-nas/claude-env.sh
export ANTHROPIC_API_KEY="sk-ant-..."
export ZAI_API_KEY="7a5d9979..."Each machine symlinks ~/.claude-env.sh to the NAS copy, and .bashrc sources it. To rotate a key, edit one file — done.
Automated Setup#
Setting this up on a new machine is a single command: /mnt/claudecode-nas/setup-sync.sh. The script symlinks directories and files, sets up API keys, backs up any existing local data, and is fully idempotent.
Layer 2: Syncthing for Project Files#
You could store projects on the NAS too, but that has real downsides:
- I/O performance: SMB adds latency. Compiling, testing, and git operations are noticeably slower
- Offline access: If the NAS goes down, you can’t work
- Node modules: Tens of thousands of tiny files that SMB handles poorly
Syncthing keeps a full local copy on each machine and syncs changes peer-to-peer. You get full local disk performance with automatic synchronization.
sudo apt install syncthing
systemctl --user enable --now syncthingConfigure it through the web UI at http://localhost:8384, share the ~/claudecode/projects/ folder between machines, and you’re done. Changes propagate within ~10 seconds.
Why Not Just Git?#
Most of these projects are git repos with GitHub remotes. But Syncthing syncs everything git doesn’t: uncommitted changes, staged files, stashes, local configs, and non-tracked files. No need to commit half-done work just to continue on another machine. Git remains the source of truth for committed code; Syncthing just makes the working directory portable.
Layer 3: Split Changelogs#
Claude Code writes session changelogs — summaries of what was done. I had all 140+ in one flat directory, but they’re really two different things:
- Machine-specific work: “Set up Samba on john-ai”, “Fixed Proxmox VM” — meaningless on other machines
- Project-specific work: “Added games to Tiltbox”, “Refactored cc-switch” — relevant everywhere
So I split them:
~/claudecode/changelogs/
├── john-ai/ ← Machine-local, not synced
└── john-ThinkPad-E15/ ← Machine-local, not synced
~/claudecode/projects/
├── Tiltbox/
│ └── changelog.md ← Project changelog, synced via Syncthing
├── cc-switch/
│ └── changelog.md ← Project changelog, synced via SyncthingThe /changelog custom command was updated to route accordingly — project changelogs travel with the project, machine changelogs stay local.
The Complete Picture#
┌─────────────────────────────────────────────────────┐
│ john-ai (Desktop) │
│ │
│ ~/.claude/ │
│ ├── settings.json ──┐ │
│ ├── commands/ ───────┤ NAS Symlinks │
│ ├── skills/ ─────────┼─────► /mnt/claudecode-nas/ │
│ ├── plugins/ ────────┤ (Synology SMB share) │
│ ├── projects/ ───────┘ │
│ └── (sessions, cache, etc.) ← Machine-local only │
│ │
│ ~/claudecode/projects/ ◄══ Syncthing ══► (laptop) │
│ ~/claudecode/changelogs/john-ai/ ← NOT synced │
└─────────────────────────────────────────────────────┘The laptop has the same symlink structure pointing to the same NAS share, the same Syncthing folder, and its own machine-local changelogs.
Trade-offs#
NAS dependency: If the NAS goes down, Claude Code falls back to defaults and you lose customization. Fine for an always-on home network, less ideal for a frequently disconnected laptop.
Symlink quirks: Some tools resolve symlinks when you cd into them. Git and Claude Code handle this fine.
Syncthing conflicts: Simultaneous edits on both machines create .sync-conflict files that need manual resolution. Rare in practice since you’re usually on one machine at a time.
Absolute paths: Some plugin config uses absolute paths like /home/john/.claude/plugins/cache/.... This works because both machines share the same username and home path. If they didn’t, plugins would need special handling.
Unencrypted secrets: API keys are in plaintext on the NAS. The share is password-protected and local-network-only, but for production use, consider a secrets manager.
Adding a Third Machine#
- Mount the NAS share at
/mnt/claudecode-nas - Run
/mnt/claudecode-nas/setup-sync.sh - Install Syncthing, pair with existing devices, share the projects folder
source ~/.bashrc
Done in about five minutes — most of that is waiting for Syncthing’s initial sync.
By the Numbers#
| Metric | Value |
|---|---|
| Projects synced | 30 directories (~253,000 files) |
| Custom commands shared | 8 slash commands |
| API keys centralized | 2 (Anthropic, z.ai) |
| Setup time for new machine | ~5 minutes |
The whole setup leans on simple, battle-tested tools — SMB mounts, symlinks, and peer-to-peer sync — rather than trying to build a custom synchronization layer. It works because Claude Code’s own directory structure naturally separates shared config from machine-local state. If you’re using Claude Code across multiple machines, give it a try.