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
npm install -g @headband/cli
headband --helpRunning 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.
headband login
headband whoami- The CLI prints a short code and opens the approval page in your browser.
- Sign in to the dashboard, check the code matches, and click Approve.
- 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.
| Command | What it does |
|---|---|
login --url <url> | Log in to a Headband other than https://headband.dev. |
whoami | Checks 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. |
logout | Deletes 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.
export HEADBAND_API_KEY="hb_adm_YOUR_ADMIN_KEY"
headband indexes list --json- Pass
--yesto answer confirmations. When stdin is not a terminal, a command that needs a confirmation fails at once withconfirmation_requiredinstead of waiting. - Pass
--jsonto 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 jsonfor one array,--out <file>to write a file).
Indexes, Documents and Search
headband indexes create products --primary-key id
headband docs push products.json --index products
headband search products "running shoes" --limit 5
headband tasks listindex is an alias of indexes: headband index switch-engine products --engine visor is the same command as headband indexes switch-engine.
| Command | What it does |
|---|---|
indexes list | create | delete | stats | Manage indexes. create takes --primary-key, --engine and --instance <id> to place the index on a dedicated engine. |
indexes settings get | set | Read 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 | revoke | Manage 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 | delete | Manage projects. create needs --engine. delete refuses a project that still has indexes: delete them first. |
Dedicated Engines
headband instances create meilisearch --lane serverless --memory 1g
headband instances list
headband instances connect <id> --client node| Command | What 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
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>| Command | What it does |
|---|---|
branch list | List 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.
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| Command | What 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 | remove | Inspect, 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 | preview | Check 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 status | One 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.
| Command | What it does |
|---|---|
sync init | Print 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 worker | Drain 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 reconcile | Count 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-letters | Send rows that kept failing back to the queue. |
sync status | Beside 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).
headband schema diff
headband schema generate --slug add-brand-facet
headband schema apply
headband schema statusheadband.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 code | When |
|---|---|
| 0 | The command succeeded. Answering no to a delete in indexes, keys, instances or schema apply also exits 0. |
| 1 | Any 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. |
| 2 | Bad usage, or the API answered 400, 413 or 422. |
| 3 | Not logged in, or the API answered 401. |
| 4 | The API answered 402 or 403. |
| 5 | Not found: the API answered 404 or 410. |
| 6 | Conflict: the API answered 409. |
| 7 | Rate limited: the API answered 429. |
| 8 | The server or the engine failed: the API answered 5xx. |
| 130 | Interrupted. |