Sync
Bidirectional sync between your Roam graph and local markdown files. Edit in Roam or in your editor — changes flow both ways.
roam sync # pull changes from Roam
roam sync --direction push # push local edits to Roam
roam sync --direction both # pull then pushHow it works
Pull (remote → local)
Queries the Roam API for the full page list (1 API call)
Queries pages modified since last sync using
:page/edit-time(1 API call)Compares against locally tracked pages in ChronDB
Pulls only new or modified pages (1 API call per page)
Writes markdown files to the sync directory
Commits and pushes to git remote (if configured)
Daily notes are synced first (most recent first), then regular pages.
Push (local → remote)
Reads all local
.mdfilesParses markdown back into Roam's block tree structure
Pulls current state from Roam to get block UIDs
Diffs local blocks against remote blocks by position in the tree
Applies changes to Roam via API:
Updated blocks → content changed in place
New blocks → created with parent UID and children
Deleted blocks → removed from Roam
Bidirectional (--direction both)
--direction both)Runs pull first, then push. Safe ordering — remote changes are downloaded before local changes are pushed, avoiding blind overwrites.
Output structure
Page titles with / \ : * ? " < > | are replaced with _ in filenames.
Markdown format
Files use a simple format that round-trips cleanly with Roam:
Each - line is a block. Indentation (2 spaces per level) represents nesting. Roam syntax ([[links]], ((refs)), {{commands}}) is preserved verbatim.
Flags
--direction
pull
Sync direction: pull, push, or both
-d, --dir
config sync.dir
Output directory for markdown files
--daily
false
Include daily notes
--dry-run
false
Show what would change, don't write
--concurrency
5
Parallel page fetches
--filter
none
Only sync pages matching this prefix
--history
none
Show version history for a page UID
Examples
Configuration
Override via environment variables:
ROAM_SYNC_DIR
sync.dir
ROAM_SYNC_DB__DIR
sync.db_dir
ROAM_SYNC_REMOTE
sync.remote
Git remote
When remote is configured, roam sync automatically commits and pushes markdown files after each sync. This gives you a versioned backup of your notes on GitHub, GitLab, or any git remote.
The git repo is initialized automatically in the sync directory on first run. SSH keys from your system are used for authentication.
Change detection
Pull uses Roam's :page/edit-time attribute to detect which pages changed since the last sync. This catches direct edits and changes to blocks referenced on the page.
Push compares local markdown against the current Roam state by position in the block tree. Blocks are matched by their order — content differences generate updates, missing blocks generate deletions, extra blocks generate creations.
Storage
Sync state is stored in ChronDB, a git-based key/value database. It tracks which pages have been synced, the last sync timestamp, and provides version history.
Default location: ~/.config/roam-tui/.chrondb
Graceful interruption
Press Ctrl+C during sync to stop gracefully. The current page finishes, all progress is saved to ChronDB, and markdown files already written remain on disk. Run roam sync again to continue from where you left off.
If ChronDB's index gets corrupted (e.g., from a hard kill), it's rebuilt automatically from git data on the next run.
API usage
First sync (500 pages)
501 (1 list + 500 pulls)
Re-sync (nothing changed)
2 (list + modified check)
Re-sync (3 pages changed)
5 (list + modified + 3 pulls)
Push (10 files changed)
10 pulls + N writes
Last updated
Was this helpful?