@restora/cli
v0.4.4
Published
Local, privacy-first scheduled Notion backups to your own storage — Google Drive, S3 (AWS/Backblaze B2/Cloudflare R2/Wasabi/DO Spaces), or a local folder. Runs on your machine — nothing is stored on any server.
Downloads
2,948
Maintainers
Readme
Restora CLI — scheduled Notion backups to your own storage
Local, privacy-first automatic backups. The CLI runs on your machine, holds your credentials
locally (~/.restora/config.json, owner-only), and streams your Notion workspace straight into a
destination you own — Google Drive, any S3-compatible bucket (AWS, Backblaze B2, Cloudflare R2,
Wasabi, DigitalOcean Spaces), or a plain local folder. No Restora server is ever involved — there
is nothing on our servers to leak.
Why this design:
- Notion internal-integration token (not OAuth) → it never expires, so scheduled backups never hit the 30-day OAuth reconnect wall, and the token never leaves your machine.
- You own the destination → Google Drive uses the
drive.filescope (the tool only sees files it created); S3 uses your own bucket + keys; local is just a folder on disk. Nothing is stored by us.
For users — one command
npx @restora/cli setupThe wizard walks you through it: connect Notion → share your databases → connect Google Drive (one click)
→ pick a daily time → first backup. Re-run anytime to change things. Prefer it installed?
npm i -g @restora/cli, then restora setup.
Other commands:
restora status # what's connected, schedule, last backup
restora backup # back up now → Google Drive
restora backup --databases id1,id2 # back up a subset (remembered for scheduled runs)
restora backup --to local --dir ./bk # back up to a local folder instead
restora connect s3 # connect your own S3-compatible bucket (see below)
restora backup --to s3 # back up to your bucket
restora backup --keep 30 # keep only the newest 30 backups
restora backup --keep-weeks 8 # also delete backups older than 8 weeks (newest is always kept)
restora schedule --daily 02:00 | --remove
restora guard # snapshot BEFORE letting an AI agent loose (see below)
restora guard --report # exactly what that agent changedInspect your backups (offline, read-only)
Point these at your backup files — the newest in your local folder by default, or any file with
--file <path>. All run entirely on your machine, make no network calls, and never change anything.
They return proper exit codes, so they drop straight into CI or a pre-commit hook.
restora doctor # one-shot health check: connections, latest backup, integrity, freshness
restora validate # is this a well-formed backup file? (exit 1 if not)
restora verify # integrity: files present, decode cleanly, relations intact (exit 1 if not)
restora stats # counts: databases, rows, views, relations, files
restora inspect # duplicate rows/databases, broken rollups, detached pages
restora tree # the workspace hierarchy at a glance
restora search "launch email" # full-text search across titles, properties, and page content
restora diff old-backup.json new-backup.json # what changed between two snapshots (databases, rows, schema)Same pure engines as the web app and the MCP server — just printed to your terminal.
Before you let an AI agent loose: restora guard
AI agents — Notion AI, MCP-connected assistants, bulk-edit scripts — can now edit and delete across your
whole workspace in seconds. guard is the seatbelt:
restora guard --label "before-cleanup-agent" # full snapshot, kept out of your normal backup history
# ... let the agent run ...
restora guard --report # rows added/removed/EDITED, schema changes, pages — offlineThe report names exactly what changed (row and page titles, property changes), and both snapshots are
full backups — if the agent broke something, restore the "before" file at
app.restora.cc. For pipelines: --json prints the diff as JSON, and
--fail-on-changes exits 1 when anything changed (CI gate for "this automation must not touch Notion").
Migrate in, export out (free, local)
restora import-obsidian ./MyVault --parent <notion-page-url> # Obsidian vault → Notion, images included
restora export-md <notion-page-url> --out page.md # any Notion page → clean Markdown
restora export-md <url> --images download # ...with images saved alongsideBoth run entirely on your machine with your own token — migration is never paywalled.
Bring your own bucket (S3-compatible)
restora connect s3 connects AWS S3, Backblaze B2, Cloudflare R2, Wasabi, or DigitalOcean Spaces — no
Restora setup required, you just supply your own bucket + keys (stored locally only, never sent to us). It
asks for the provider, region/endpoint, bucket, and an access key/secret (use a key scoped to just that
bucket: PutObject, ListBucket, DeleteObject). Then restora backup --to s3. Note: on S3, retention
(--keep / --keep-weeks) permanently deletes old backups — enable bucket versioning if you want
recoverability.
Use your backups from any AI agent (MCP)
restora mcp runs a local, read-only MCP server that lets any
MCP-capable AI agent — Claude Desktop, Cursor, Cline, Continue, Zed, ChatGPT desktop, and more — read
the backups already on your machine. Ask "what was in my Projects database last week?", "map my whole
workspace", or "what changed since this backup?" and the agent answers by calling the server's tools.
Privacy by design: Restora makes no LLM calls, holds no API key, and — in its default mode — makes zero network calls. Your own agent does the reasoning over local JSON. Every tool is read-only, so even if a backup contains malicious text it can't trigger any action. (The store-nothing posture, but stronger.)
Get the config snippet to paste into your agent:
restora mcp --print-configThen add it to your agent (same shape everywhere):
{ "mcpServers": { "restora": { "command": "npx", "args": ["-y", "@restora/cli", "mcp"], "env": {} } } }By default it reads your local-backup folder (~/Restora Backups, or whatever you set). Point it elsewhere
with --dir <folder> or --file <backup.json>.
Tools exposed: list_backups, describe_backup (workspace map: databases, properties, relations, views),
query_database (rows with readable values; relations resolved to the linked page titles), get_page
(a page as Markdown), search, and read_id_map (old→new ids after a restore, to repoint
integrations/webhooks).
Live drift audit (opt-in): add --allow-live to also expose run_drift_audit, which compares a backup
against your current Notion (deleted/emptied databases, removed properties, type changes) — the input
for a restore plan. This is the only tool that uses the network, and only to your own Notion (it needs
restora connect notion); it never calls an LLM or a Restora server.
Very large workspaces (memory)
Backups stream to disk as they're fetched — each database and file is written out and released, so
even multi-GB workspaces don't need a big heap (upload destinations briefly use ~the backup's size in
temp disk while shipping). The CLI also raises Node's heap automatically for backup as
belt-and-suspenders. If a truly enormous single database still runs out of memory:
restora databases # list your databases + their ids
restora backup --databases id1,id2 # back up a batch; repeat for the nextNote: a relation from a database in one chunk to a database in another chunk won't resolve across separate files — group related databases into the same run where you can.
Limitations (stated honestly)
- Scheduled backups run only when this machine is on and awake at the scheduled time.
- Scheduling writes a small runner to
~/.restoraand registers it with the OS scheduler (Windows Task Scheduler / cron). Logs go to~/.restora/backup.log. - Files larger than 20MB inside Notion are not bundled — that's Notion's File Upload API limit (single-part uploads cap at 20MB), so a bigger file couldn't be restored anyway. The link is kept.
