Repo (Push / Pull)
butterbase repo
Section titled “butterbase repo”butterbase repo syncs a folder to your app’s repo snapshots. Pushes are content-addressed: unchanged files aren’t re-uploaded. The five most recent snapshots are retained.
Repo storage is not the same as butterbase storage (user-uploaded files). It’s a dedicated, reserved area for your app’s source code. Limits: 10 MB per file, 100 MB per snapshot.
Bind a folder to an app
Section titled “Bind a folder to an app”butterbase repo init <app_id>Writes .butterbase/config.json with currentApp set, and seeds a .butterbaseignore if none exists. Use --force to overwrite an existing .butterbase/config.json (the pinned_snapshot_id and other fields are preserved). Use --no-ignore to skip the .butterbaseignore seed.
butterbase repo push [--message "<text>"] [--dry-run] [--json]Walks the folder, hashes each file, calls the server’s prepare endpoint, uploads any blobs the server doesn’t already have, and commits. On success, updates .butterbase/config.json with the new pinned_snapshot_id.
--dry-run prints the manifest summary (sha + size + path per file) without contacting the API. Useful for inspecting what would be pushed.
butterbase repo pull [--force] [--json]Three-way reconcile against the pinned snapshot:
- Files in the remote
latestthat don’t match local → fetched and overwritten. - Files locally that aren’t in
latest:- If their content matches the pinned snapshot (you haven’t touched them), deleted silently.
- Otherwise flagged as a conflict; exits with code 1 unless
--forceis passed.
If the pinned snapshot has been pruned server-side, untracked-local deletions always require --force.
Status
Section titled “Status”butterbase repo status [--json]git status-style summary:
Mmodified locally vs the pinned snapshot?untracked (not in pinned)Ddeleted (in pinned, missing locally)Nnew on remote (inlatestbut not in pinned and not locally — pull would bring it in)
History and wipe
Section titled “History and wipe”butterbase repo log [--json] # snapshot history newest-firstbutterbase repo wipe # destructive — name-confirm promptIgnore rules
Section titled “Ignore rules”Three layers, highest-precedence wins:
.butterbaseignore(negates a default with!path).gitignore- Hardcoded defaults:
.git/,node_modules/,dist/,.next/,.turbo/,.DS_Store,.butterbase/
App visibility
Section titled “App visibility”butterbase visibility <public|private> [--listed|--unlisted] [--app <id>]Marks the app public or private. When public, --unlisted hides it from the templates browse listing (/v1/templates, the dashboard Templates page, and butterbase templates) while still allowing clone by direct app id.
Clone a public app
Section titled “Clone a public app”butterbase clone <source_app_id> [target_dir] [--name "<text>"] [--region <region>] [--json]Creates a fresh, owned app cloned from a public template. The CLI:
- Calls the clone endpoint to start a job.
- Polls until the job completes (max 5 minutes).
butterbase repo init <new_app_id>+butterbase repo pullin<target_dir>(defaults to a dir named after the new app id).
Clones receive the source’s schema, RLS policies, function code, non-secret config, repo files, and rows from _seed: true tables. End-user accounts, secrets, env vars, BYOK AI keys, custom domains, and audit logs stay with the source. See What a clone copies for the full breakdown.
The butterbase clone command prints any warnings returned by the clone job — for example, if the source’s auth_hook_function references a function that didn’t replay onto the destination, the binding is left NULL and a warning is printed.
If the clone fails, the error is printed and exit code is 1. Failed jobs can be retried via the HTTP API directly (POST /v1/clone-jobs/<job_id>/retry).