Skip to content

The Bailey CLI

bailey is an optional command-line companion to the dashboard. It publishes folders to a live URL, lists your sites, reads collected submissions, runs erasure requests, and can run a local sandbox with real storage before you ship.

Terminal window
curl -fsSL https://dl.trybailey.app/install.sh | sh

The installer detects your OS and CPU, downloads the right binary, verifies its SHA-256 checksum, and drops it in ~/.local/bin. If that folder isn’t on your PATH, the script tells you the line to add.

Terminal window
iwr -useb https://dl.trybailey.app/install.ps1 | iex

Same idea: it verifies the checksum, installs to %LOCALAPPDATA%\Bailey\bin, and adds that folder to your user PATH. Open a new terminal afterwards.

Check it worked:

Terminal window
bailey version
bailey help

There are two ways to sign in, depending on who’s running the command.

Terminal window
bailey login

This opens your browser to sign in (the same login as the dashboard), then stores your credentials locally in ~/.config/bailey/credentials.json (0600). No token to copy or paste. Run bailey logout to clear them.

A CI runner can’t open a browser. Instead, mint a deploy token from the dashboard (Account → Deploy tokens), choose its scope (your whole profile, or specific sites), and hand it to the CLI through the BAILEY_TOKEN environment variable:

Terminal window
export BAILEY_TOKEN=blt_
bailey deploy ./dist --app my-site

A deploy token can only do what its abilities allow — publish (bailey deploy) and/or pull files (bailey pull), never read collected data, erase, or change account settings — and is revocable and audited. Keep it in your CI’s secret store, not in your repo.

Terminal window
bailey deploy [dir] [--app <label>] [--org <org>] [--spa] [--public <bucket>]… [--collect <bucket>]…

Publishes <dir> as a new version of the site <label> and prints the live URL. If the site doesn’t exist yet, it’s created for you. In a linked folder (see bailey link below), a plain bailey deploy is enough — no flags to retype.

Naming a folder publishes that folder, and its link is the one read there. Naming none lets the link of the current folder decide: its dir if it has one (a repo whose site is built into build/), the current folder otherwise. Whatever you type wins, one dimension at a time — a typed folder isn’t overridden by the link’s dir, a typed --app isn’t overridden by the link’s app.

  • --app <label>: the site’s address label (validated; reserved labels are rejected).
  • --spa: single-page app. A page visit that matches no file falls back to index.html (200), so reloading /about works. Missing assets still return 404. Off by default: a static site keeps honest “not found”s. --spa=false turns it back off; omitting the flag changes nothing (the site keeps whatever it had). Equivalent to "spa": true in bailey.manifest.json. See Apps that reload to a “Page not found”.
  • --public <bucket>: declare a public key-value bucket (readable and writable from the page). Repeatable.
  • --collect <bucket>: declare an insert-only collection bucket (write-only from the page). Repeatable.

Each deploy is a new version (atomic swap) and amends the site’s manifest; it never wipes your existing buckets.

Terminal window
bailey deploy ./dist --app my-site --collect contact --collect signups --public votes
Section titled “bailey link: remember where a folder publishes”
Terminal window
bailey link <app> [dir] [--org <org>] [--dir <folder>]

Links a folder to a site by writing a small .bailey.json next to your files (and adding it to the folder’s .gitignore — the link is about your machine, it never belongs in the repo and is never published). Once linked, a plain bailey deploy publishes the folder — app and organization included. Run bailey link with no argument to see where the current folder points; explicit --app / --org flags always win over the link.

The two folders in that line don’t mean the same thing, and both are needed: the positional [dir] is where the link lives, --dir <folder> is what it publishes.

  • --dir <folder>: the folder to publish, relative to the link. Use it when your site is built — the link stays at the repo root, where it survives, and points at build/, which your build tool wipes and recreates on every run. Omitting --dir on a re-link keeps the folder already recorded; --dir . clears it.
Terminal window
# A built site: link once at the root, then publish with a bare command, forever.
bailey link my-site --dir build
npm run build && bailey deploy # publishes build/, announced before the upload

bailey pull links the folder automatically on first fetch, so the everyday loop is just: bailey pull my-site → edit → bailey deploy. A pulled folder is the site, so it gets no --dir.

bailey dev follows the same link: with no folder named, it serves the one --dir records, so the sandbox and the deploy never disagree on which folder is the site.

Terminal window
bailey pull <app> [dir] [--org <org>] [--force]

Downloads the site’s current version — files, governance manifest (bailey.manifest.json) and mail templates — into dir (default: the current folder), so you can edit locally and republish with bailey deploy (the folder comes out linked, so no flags are needed). The bundle is self-sufficient: a pull → deploy round-trip keeps your declared buckets and routing intact. It refuses to write into a non-empty folder unless you pass --force.

Terminal window
bailey dev [dir] [--port 8788]

Serves <dir> on http://127.0.0.1:8788 with real storage (kv / counter / collect) so you can test your data wiring before publishing. It’s a throwaway sandbox: the data is local and disposable, and nothing goes to production. No account needed.

Name no folder in a link that records a --dir and the sandbox serves that one — the same folder bailey deploy would publish.

Terminal window
bailey list [--org <org>]

Prints a table of your sites — your personal space by default, or an organization’s fleet with --org:

APP NAME URL
my-site Vengeful Castiel https://my-site.trybailey.app/

The APP column is the value the other commands take: bailey pull <APP>, bailey deploy --app <APP>. The display name doesn’t target anything.

Terminal window
bailey orgs

Lists the organizations you belong to, with your role and the slug to pass as --org. By default every command works in your personal space; add --org <slug> to list, deploy, pull, data or erase to target a project that lives in an organization instead. Your rights there are the same as in the dashboard (enforced server-side), and a new site deployed with --org is created inside that organization.

Terminal window
bailey data <app> <bucket> [--org <org>]

Dumps a collection bucket as JSON lines (owner-only). The dashboard’s Collected data tab does the same with no terminal; see Reading & erasing collected data.

Terminal window
bailey erase <app> <email> [--org <org>]

Removes every record matching <email> across all of the app’s buckets. The same action is available from the dashboard under Data & privacy → Erase a person’s data.

Terminal window
bailey version # prints the installed version
bailey help # or -h, --help

A minimal GitHub Actions step, once BAILEY_TOKEN is set as a repository secret:

- name: Publish to Bailey
run: |
curl -fsSL https://dl.trybailey.app/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
bailey deploy ./dist --app my-site
env:
BAILEY_TOKEN: ${{ secrets.BAILEY_TOKEN }}

If the site belongs to an organization, add its scope — bailey deploy looks in your personal projects by default:

Terminal window
bailey orgs # your organizations and their slug
bailey deploy ./dist --app my-site --org acme

Without it the CLI doesn’t find the project, tries to create it, and stops on subdomain "my-site" is not available (already taken) — the address is taken by your own project, in a scope it wasn’t looking at. A deploy token scoped to selected projects behaves the same way: it only ever sees those.

Whether you declare buckets here (--public / --collect), in a bailey.manifest.json shipped with your files, or from the dashboard’s Data & privacy screen, they reconcile into the same governed set, and writes from the SDK only work once the bucket exists.

Hosted on Bailey