Guide 8 min read

How to Sync Shell History Across Machines (Without the Cloud)

Want the same shell history on every machine? Here are the real options for syncing Bash/Zsh history across machines — and how to do it locally, without a cloud account.

Madhubalan Appachi Madhubalan Appachi ·

If you work across a laptop, a desktop, and a few servers, it's maddening that each one has its own separate command history. The command you ran on the laptop yesterday is nowhere to be found on the server today. So how do you get one unified shell history across all your machines? Here are the real options — and how to do it without handing your history to a cloud service.

Option 1: Manually sync the history file (don't)

The obvious idea is to put ~/.zsh_history (or ~/.bash_history) in Dropbox, a git repo, or an rsync job. It almost works, and then it doesn't:

  • Concurrent writes corrupt it. Two machines (or two terminals) writing the same flat file leads to interleaved lines, conflicts, and lost commands.
  • No real merge. A history file has no notion of merging two timelines — last write wins, so you quietly lose history.
  • It's all-or-nothing. You can't sync some context (commands) without the format's limitations (no metadata, no dedup, no ranking).

For a one-machine backup it's fine. As a multi-machine sync strategy, the flat-file approach fights you.

Option 2: A tool with built-in cloud sync

Atuin is the best-known option here: it stores history in SQLite and offers end-to-end encrypted sync through a server (hosted, or self-hosted if you'd rather run your own). If continuous, automatic cross-machine sync is your single most important requirement, this is the most turnkey path — just know that it means running or trusting a sync server, even with encryption.

Option 3: Local-first encrypted export / import

If you'd rather your history never stream to any server, the cleaner model is to move it deliberately. Suvadu stores everything in a local SQLite database and gives you explicit export / import that merges cleanly across machines — no account, no daemon, no cloud.

How it works

On the source machine, export your history to a file:

suv export > history.jsonl

Move that file to the other machine however you already move files — scp, a synced folder, a USB stick, your encrypted backup. Then import it:

suv import history.jsonl

Suvadu merges the imported commands into the local database rather than overwriting it, so you can pull history in from several machines and end up with one combined timeline — without the corruption you'd get from syncing a raw file. You can also scope an export (for example, only commands after a date) when you just want recent history. See import / export for the full options.

Why this is the safer default

  • Nothing leaves your machine unless you send it. There's no background sync and no server in the loop — you decide what moves and when.
  • Clean merges. Because history lives in a database with real metadata, importing combines timelines instead of clobbering them.
  • You can encrypt the transport you already trust. Put the export file through scp or your existing encrypted backup and the data is protected end to end, your way.

Which should you choose?

  • Need always-on, automatic sync across many machines (and you're fine running/trusting a server)? Atuin's cloud sync is the most hands-off.
  • Want unified history without a cloud, on your own terms? Suvadu's local-first export / import gives you cross-machine history with nothing phoning home.
  • Just backing up one machine? Even a plain export to your backup beats trusting SAVEHIST not to truncate.

For most developers who care about privacy, deliberate export / import hits the sweet spot: one history across your machines, zero cloud dependency.

Install Suvadu →  ·  Why upgrade from built-in shell history →

Madhubalan Appachi
Madhubalan Appachi

Builder of Suvadu. Writes Rust, thinks about shell history more than most people, and believes developer tools should be local-first.