CLI

The headband command manages indexes, documents, keys, dedicated engines, branches, Sync and schema migrations from your terminal. This page covers @headband/cli 0.7.0, the version on npm. A command marked Requires CLI 0.4.0 (or a later version) is missing from older installs: check yours with headband --version and update with npm install -g @headband/cli@latest.

Run headband --help for every command, or headband <command> --help for one.

Install

terminal
npm install -g @headband/cli
headband --help

Running headband with no command starts headband init, which sets up search in the current project.

Log In

headband login uses a device code, so you never paste a key into the terminal.

terminal
headband login
headband whoami
  1. The CLI prints a short code and opens the approval page in your browser.
  2. Sign in to the dashboard, check the code matches, and click Approve.
  3. The CLI picks up its key and saves it.

The code expires after 15 minutes. Approval creates an organization-wide admin key named after your machine. Besides the normal admin permissions, it can manage keys, projects and schema migrations. Only login keys get those three permissions.

The key is saved in ~/.config/headband/credentials.json (or $XDG_CONFIG_HOME/headband/credentials.json), readable only by you. Each login is a named profile. login --profile <name> picks the name, and the newest login becomes the current profile.

CommandWhat it does
login --url <url>Log in to a Headband other than https://headband.dev.
whoamiChecks the saved key against the API and prints the org and key prefix.
profiles list | use <name>List saved logins, or switch the current one. --profile <name> (or HEADBAND_PROFILE) picks one for a single command.
logoutDeletes the saved key. It first asks whether to revoke the key on the server too. --yes revokes it without asking; --no-revoke keeps it working.

Every command takes --url (or HEADBAND_URL). Without it, the CLI uses the current profile.

Scripts and Agents

Scripts, CI and coding agents do not need a browser login. Pass a key with --token <key> or the HEADBAND_API_KEY environment variable. It wins over any saved login. Create the key in the dashboard, or with headband keys create.

terminal
export HEADBAND_API_KEY="hb_adm_YOUR_ADMIN_KEY"
headband indexes list --json
  • Pass --yes to answer confirmations. When stdin is not a terminal, a command that needs a confirmation fails at once with confirmation_required instead of waiting.
  • Pass --json to print one JSON document on stdout. Errors then print one JSON object on stderr (see Output and Exit Codes).
  • headband docs export --index <uid> pulls every document as JSON lines (--format json for one array, --out <file> to write a file).

Indexes, Documents and Search

terminal
headband indexes create products --primary-key id
headband docs push products.json --index products
headband search products "running shoes" --limit 5
headband tasks list

index is an alias of indexes: headband index switch-engine products --engine visor is the same command as headband indexes switch-engine.

CommandWhat it does
indexes list | create | delete | statsManage indexes. create takes --primary-key, --engine and --instance <id> to place the index on a dedicated engine.
indexes settings get | setRead settings, or apply them from a JSON file with --file.
indexes switch-engine <uid> --engine <engine>Move the index to another engine. Its uid, keys and URLs stay. --dry-run shows what would be copied and which settings would not carry over; --accept-drops switches anyway; --wait follows the switch to the end; --status shows the latest switch.
docs push <file> --index <uid>Upload documents from a JSON file.
docs export --index <uid>Export every document as JSON lines, or one JSON array with --format json. Walks the index by cursor, so it reaches every document on every engine (requires CLI 0.5.0), and can run while the index takes writes: every document that exists for the whole export is written exactly once (see Walk a Whole Index). With --out, a failed export keeps the documents it wrote in <file>.partial (requires CLI 0.6.0). An older Visor index over 1000 documents whose primary key is not filterable and sortable is refused, and the CLI prints the settings change that fixes it.
docs delete <docId>... --index <uid>Delete one or more documents by id. Several ids in one call requires CLI 0.4.0.
search <index> <query>Search one index. Takes --limit, --filter and (requires CLI 0.5.0) --mode instant|retrieval, which picks Visor's ranking and which other engines ignore.
tasks list | get <id> --index <uid>Check async tasks. Tasks live on the engine that holds the index, so pass --index (requires CLI 0.4.0) with the login key or on a branch other than main.
keys list | create | revokeManage API keys. create takes --type admin|search, --project <id>, and (requires CLI 0.4.0) --branch <name> and --instances <id,id>. A search key always needs a project or branch. The new key prints once.
projects list | create | deleteManage projects. create needs --engine. delete refuses a project that still has indexes: delete them first.

Dedicated Engines

terminal
headband instances create meilisearch --lane serverless --memory 1g
headband instances list
headband instances connect <id> --client node
CommandWhat it does
instances create <engine>Create an engine. Takes --name, --lane, --memory (512m, 1g), --region and --idle-timeout <seconds>.
instances list | show <id>List or inspect engines.
instances wake | park <id>Start a parked engine, or park a running one.
instances update <id>Change the name, lane, memory or idle timeout.
instances wakes <id>Recent wakes and how long each took.
instances delete <id>Delete an engine.
instances connect <id>Print the endpoint plus Node or curl code for the engine's own client.

headband warm <index>... or headband warm --project <id> wakes sleeping engines ahead of traffic, with --level auto|stage|start. Requires CLI 0.4.0

See Dedicated Engines for lanes, sizes and keys.

Branches

headband branch (or branches) manages a project's branches. Requires CLI 0.4.0

terminal
headband branch create preview/pr-1 --empty --expires-in 7d --project <project id>
headband branch checkout preview/pr-1 --project <project id>
headband indexes create products --primary-key id
headband branch delete preview/pr-1 --project <project id>
CommandWhat it does
branch listList the project's branches.
branch create <name>Fork the parent (--parent, default main) with its indexes and data, copy-on-write. --empty makes an empty branch. Takes --expires-in (30m, 2h, 7d). Forking requires CLI 0.7.0: before it, create needs --empty.
branch ensure <name>For preview deploys: fork unless the branch exists, push its expiry out (--expires-in, default 7d), mint a search and an admin key, and write HEADBAND_* variables to --env-out. Requires CLI 0.7.0.
branch checkout <name>Write .headband/project.json. Every later command in that directory, or below it, works on that branch.
branch protect | unprotect <name>Block or allow deleting the branch. main, the primary branch, is always protected and cannot be unprotected.
branch expire <name>Delete the branch later: --in 7d, --at <ISO time>, or --clear.
branch delete <name>Delete the branch, its indexes, its keys and its engine.

The project comes from --project, else the directory's checkout. On any command, --branch <name> works on another branch for one call: the CLI sends the Headband-Branch header for you.

Sync

headband sync source and headband sync index drive managed Postgres Sync: Headband reads your database and keeps an index up to date. You can also use the Sync page in the dashboard or the /v1/sync API.

terminal
export HEADBAND_SYNC_DB_URL="postgres://sync_user@db.example.com:5432/app"
headband sync source add app-db
headband sync source setup <sourceId>
headband sync source test <sourceId>
headband sync index create -f products.sync.json
headband sync status
CommandWhat it does
sync source add <name>Register a Postgres database. Takes --db-url (or HEADBAND_SYNC_DB_URL), --tls-mode verify-full|require and --ca-file.
sync source setup-sql <id>Print the SQL that creates the Sync role and publication.
sync source setup <id>Run that SQL on your machine as the tables' owner (--owner-url or HEADBAND_SYNC_OWNER_URL). The owner URL never leaves your machine.
sync source list | show | test | set-ca | removeInspect, test the connection, change the CA, or remove a source.
sync index create | update -f <file>Create an index from a .sync.json definition, or save a new version. update --rebuild applies it now.
sync index validate | previewCheck a definition, or render up to 20 documents (--ids) without writing anything.
sync index rebuild | pause | resume <id>Rebuild into a new index and swap, or stop and restart applying changes.
sync index check <id>Reserved for drift checks. They are not available yet: the API answers 501 not_in_this_release.
sync index remove <id>Stop syncing. Add --drop-index to delete the engine index too.
sync statusOne table of every source and index, with lag.

Self-hosted sync from your ORM

With @headband/sync 0.1.0 and @headband/drizzle 0.1.0, your own process keeps indexes in step with your tables through an outbox table. These commands read headband.config.ts and DATABASE_URL. See Self-Hosted Sync for the setup.

CommandWhat it does
sync initPrint the outbox table's SQL. --write saves it to headband/outbox.sql; --apply (requires CLI 0.4.0) creates it in DATABASE_URL, safe to re-run.
sync workerDrain the outbox and write the documents. It runs until stopped by default, so --loop matters only with --budget-ms, which stops after that long, for cron (--loop then waits for changes until the budget ends instead of exiting on an empty outbox). Each batch prints one line to stderr (requires CLI 0.6.0). --scaffold docker writes a Dockerfile.
sync reconcileCount the missing and extra documents per index. --fix repairs them. Reads the index's ids by cursor, so a Visor index past 1000 documents is compared id by id too (requires CLI 0.5.0). --content also compares each document with its source row and counts the stale ones, which --fix rewrites (requires CLI 0.6.1).
sync retry-dead-lettersSend rows that kept failing back to the queue.
sync statusBeside a headband.config.ts: the outbox's pending rows, dead letters and oldest pending row (requires CLI 0.4.0). Elsewhere: managed Sync, as above.

Schema Migrations

The schema commands compare the indexes declared in headband.config.ts with what Headband has, and write migration files to headband/migrations (change it with --dir).

terminal
headband schema diff
headband schema generate --slug add-brand-facet
headband schema apply
headband schema status

headband.config.ts must export both the config (as its default export) and the adapter. schema apply needs the adapter, because it backfills documents from your database. A migration that removes an index fails unless you pass --allow-destructive.

Applied migrations are read from the server, so a fresh checkout or CI can run schema apply without headband/migrations/.applied.json. That file is an optional local cache.

headband schema forget <index> clears the recorded schema state of an index you deleted some other way, so the next schema generate plans it as new. It does not touch any index. Requires CLI 0.4.0

Output and Exit Codes

With --json, a command prints one JSON document on stdout. An error then prints one JSON object on stderr, with error, code, status (the HTTP status, or null) and exitCode. Without it, the message goes to stderr.

Exit codeWhen
0The command succeeded. Answering no to a delete in indexes, keys, instances or schema apply also exits 0.
1Any other error. Also: schema diff when there are pending changes, a sync index validate that fails, a sync index preview with errors, and answering no to a sync prompt.
2Bad usage, or the API answered 400, 413 or 422.
3Not logged in, or the API answered 401.
4The API answered 402 or 403.
5Not found: the API answered 404 or 410.
6Conflict: the API answered 409.
7Rate limited: the API answered 429.
8The server or the engine failed: the API answered 5xx.
130Interrupted.