Query and manage your Altertable data platform from the terminal.
# 1. Install
curl -fsSL https://install.altertable.ai | sh
# 2. Configure credentials
altertable profile --configure
# Or non-interactive (CI/scripts):
altertable profile --configure --api-key atm_xxxx --env production
altertable profile --configure --user your_username --password your_password
# 3. Verify (optional — the wizard verifies by default)
altertable profile show
# 4. Query
altertable query "SELECT * FROM users LIMIT 10"Recommended for most users:
curl -fsSL https://install.altertable.ai | shnpm install -g @altertable/cliRequires Bun at runtime (used as the JS engine when running the npm package).
Download the platform binary from GitHub Releases. Each release ships:
| Asset | Description |
|---|---|
altertable-darwin-arm64 |
macOS Apple Silicon |
altertable-darwin-x64 |
macOS Intel |
altertable-linux-x64 |
Linux x86-64 |
altertable-linux-arm64 |
Linux ARM64 |
altertable-cli.js |
Bun bundle (bun altertable-cli.js) |
checksums.txt |
SHA-256 checksums for all assets |
Verify and install:
shasum -a 256 -c checksums.txt --ignore-missing
chmod +x altertable-linux-x64
sudo mv altertable-linux-x64 /usr/local/bin/altertable
altertable --versiongit clone https://github.com/altertable-ai/altertable-cli.git
cd altertable-cli
git submodule update --init --recursive
chmod +x bin/altertable
export PATH="$PWD/bin:$PATH"
altertable --versionCheck for a newer CLI and install it:
altertable update
altertable update --installaltertable update --install is origin-aware:
- prebuilt release binaries update from GitHub Releases, verify
checksums.txt, then replace the current binary atomically; - npm-style installs use the package manager (npm, Bun, pnpm, or Yarn) and verify the installed
altertable --version; - source checkouts are not auto-installed by default; update them with
git pullor choose an explicit install method.
The CLI also performs a silent daily update check after successful human-facing commands. Notices are written to stderr only, never to stdout, and are disabled for --json, --agent, CI, and non-TTY output.
Control automatic notices:
altertable update --status
altertable update --check-interval weekly
altertable update --check-interval neverSet ALTERTABLE_NO_UPDATE_CHECK=1 or ALTERTABLE_UPDATE_CHECK=never to disable automatic checks from the environment. Package-manager installs use npm by default and detect Bun, pnpm, or Yarn when available; set ALTERTABLE_UPDATE_INSTALLER=bun|npm|pnpm|yarn to override. Set ALTERTABLE_UPDATE_INSTALL_METHOD=auto|package-manager|github-binary or pass --install-method to choose an installer strategy.
The CLI talks to two independent APIs with separate auth schemes:
| Plane | Purpose | Auth |
|---|---|---|
| Management (control) | profile show, catalogs |
Browser OAuth or API key |
| Lakehouse (data) | query, upload, upsert, append |
HTTP Basic |
Most users need both. Run the interactive wizard or configure each plane with flags:
# Interactive wizard (TTY) — configures management and lakehouse
altertable profile --configure
# Plane-specific wizards
altertable profile --configure --scope management
altertable profile --configure --scope lakehouse
# Non-interactive (scripts/CI)
altertable profile --configure --api-key atm_xxxx --env production
altertable profile --configure --user your_username --password your_password
altertable profile --configure --data-plane-url https://api.example.com
altertable profile show
# Verify stored credentials
altertable profile statusPassing --user and --api-key in a single invocation is not allowed. Run two separate profile --configure calls — one per plane.
altertable profile --configure --api-key atm_xxxx --env production
# Pipe the key from a secret store
printf '%s' "$KEY" | altertable profile --configure --api-key-stdin --env productionOr via environment variables:
export ALTERTABLE_API_KEY="atm_xxxx"
export ALTERTABLE_ENV="production"Sign in interactively with your browser instead of pasting an API key:
altertable login # opens your browser, stores an OAuth session
altertable logout # clears stored credentials and settings for all profilesaltertable profile --configure --user your_username --password your_passwordPrefer reading secrets from stdin to avoid exposing them in process listings:
printf '%s' 'your_password' | altertable profile --configure --user your_username --password-stdin
printf '%s' "$KEY" | altertable profile --configure --api-key-stdin --env productionPlane URLs default to HTTPS. --data-plane-url can be saved by itself without changing credentials; --control-plane-url must be saved with a management credential so failed login/configure attempts do not leave a stale control-plane override. Localhost HTTP (http://localhost, http://127.0.0.1) works without extra flags; other HTTP URLs require --allow-insecure-http.
Or via environment variables:
# Option 1: pre-encoded HTTP Basic token
export ALTERTABLE_BASIC_AUTH_TOKEN="your_basic_auth_token"
# Option 2: username/password
export ALTERTABLE_LAKEHOUSE_USERNAME="your_username"
export ALTERTABLE_LAKEHOUSE_PASSWORD="your_password"Rules for updating credentials:
- Separate
profile --configureinvocations — lakehouse and management credentials coexist in the active profile. - Within one
profile --configureinvocation — only one plane may be written. - Within the same plane — a new value replaces the previous one.
- Environment variables override stored credentials when set.
altertable logoutremoves both planes and resets endpoint overrides for all profiles.
Named profiles store credentials and endpoint overrides per environment. Global display defaults (query_layout, query_max_width, query_pager) stay in the root config and apply to all profiles.
Profile names can be provided explicitly, or derived from an organization slug and environment as <org>_<env>. Derived names are normalized to lowercase safe profile names, for example Acme + Production becomes acme_production.
# Browser login creates or reuses the signed-in org_env profile and switches to it
altertable login
# Or store the signed-in session in the current profile
altertable login --replace-profile
# Set up multiple environments with explicit profile names
altertable profile create acme_staging --api-key atm_xxx --env staging
altertable profile create acme_prod --api-key atm_yyy --env production
# Switch the sticky active profile
altertable profile use acme_staging
# Or choose interactively
altertable profile switch
# Use a profile for one command
altertable --profile acme_production profile show
# Use a profile for the current shell, including direnv
eval "$(altertable profile env acme_staging)"
# Or generate a .envrc snippet
altertable profile direnv acme_staging > .envrc
# Inspect profiles
altertable profile list
altertable profile current
altertable profile status
altertable profile show --name acme_stagingAdvanced profile commands manage endpoint overrides and inspect existing profiles:
# Verify credentials and show the profile (identity + credential details)
altertable profile status --name acme_staging
# Print a shell snippet for direnv or manual use
altertable profile env acme_staging
altertable profile direnv acme_staging
# Rename a profile
altertable profile rename acme_staging acme_stageProfile selection precedence: --profile flag → ALTERTABLE_PROFILE env var → active_profile config → default.
| Scope | Stored there |
|---|---|
Global root config |
Active profile and display/update preferences such as query layout, query width, and update checks |
| Profile-specific config | Credentials metadata, endpoint overrides, organization/principal metadata, and credential expiry timestamps |
profile status runs live credential verification and then renders profile show (identity and credential details, including OAuth and auto-provisioned lakehouse credential expiry when present) followed by the verification result. profile show --config additionally prints the config dir, profile config file, and secret store paths.
Management plane
| Priority | API key | Environment slug | Control-plane base |
|---|---|---|---|
| 1 (highest) | ALTERTABLE_API_KEY |
ALTERTABLE_ENV |
ALTERTABLE_MANAGEMENT_API_BASE |
| 2 | profile secret api-key |
profile api_key_env |
profile management_api_base |
| 3 (default) | — | — | https://app.altertable.ai |
Lakehouse plane
| Priority | Credentials | Data-plane base |
|---|---|---|
| 1 | ALTERTABLE_BASIC_AUTH_TOKEN |
ALTERTABLE_API_BASE |
| 2 | ALTERTABLE_LAKEHOUSE_USERNAME + ALTERTABLE_LAKEHOUSE_PASSWORD |
profile api_base |
| 3 | stored basic token / user+password | https://api.altertable.ai |
Note: Setting
ALTERTABLE_ENVoverrides the slug in/environments/{env}/…paths without changing the Bearer token. Make sure the env var, storedapi_key_env, and API key permissions all refer to the same environment.
You can also override endpoints per-command with flags:
| Purpose | Flag | Environment variable |
|---|---|---|
| Management / control plane | --control-plane-url |
ALTERTABLE_MANAGEMENT_API_BASE |
| Lakehouse / data plane | --data-plane-url |
ALTERTABLE_API_BASE |
Query
altertable query "SELECT * FROM users LIMIT 10"
# Human layout and script-friendly formats
altertable query "SELECT * FROM events LIMIT 3"
altertable query "SELECT * FROM events LIMIT 3" --layout auto
altertable query "SELECT * FROM events LIMIT 3" --layout table
altertable query "SELECT * FROM events LIMIT 3" --layout line
altertable query "SELECT * FROM events LIMIT 3" --columns uuid,event,timestamp
altertable query "SELECT * FROM events LIMIT 3" --max-width 24
# Serialized output
altertable query "SELECT 1" --format csv
altertable query "SELECT 1" --format json
altertable query "SELECT 1" --format markdown
# Long results — pipe through a pager
altertable query "SELECT * FROM big_table" --pager always
altertable query "SELECT * FROM big_table" --pager never
# JSON for scripting
altertable --json query "SELECT 1"
# Agent-friendly preset (structured JSON, no pager or terminal styling)
altertable --agent query "SELECT 1"Use --format human|json|csv|markdown for serialized output (default human). Human output respects --layout auto|table|line (default auto), --columns, --max-width, and --pager auto|always|never. auto picks a table when it fits and line layout when the table would be too wide. --format json|csv|markdown skips pager and layout controls. For machine-readable query output, prefer --format json or the global --agent preset.
Set display defaults in ~/.config/altertable/config:
query_layout=auto # auto | table | line
query_max_width=32 # integer >= 8
query_pager=auto # auto | always | neverAppend and upload
altertable append --catalog my_cat --schema public --table users --data '{"id": 1}'
altertable append --catalog my_cat --schema public --table users --data '{"id": 2}' --sync
altertable upload --catalog my_cat --schema public --table users --mode overwrite --format csv --file data.csv
altertable upsert --catalog my_cat --schema public --table users --primary-key id --format csv --file data.csvInspect async operations
altertable query show <query-uuid>
altertable query cancel <query-uuid> --session-id <uuid>
altertable append status <append-id>Product-level commands stay at the top level. The full management REST surface is available via altertable api (HTTP invoker):
altertable profile show
altertable catalogs list
altertable catalogs create --engine altertable --name "My Catalog"
# Explore the bundled OpenAPI contract
altertable api spec
altertable api spec --json # raw JSON document
altertable api routes # index of paths and methods
altertable api routes createDatabase
# HTTP calls — path is relative to /rest/v1 (base URL from config)
altertable api /whoami
altertable api GET /whoami
altertable api GET /environments/production/connections
altertable api GET '/environments/production/connections?limit=10'
altertable api -X GET /service_accounts -f label="CI Bot"
altertable api POST /service_accounts -f label="CI Bot"
altertable api /service_accounts -f label="CI Bot" -F enabled=true
altertable api POST /environments/production/databases -f name=Analytics
altertable api POST /environments/production/databases --body '{"name":"Analytics"}'
altertable api POST /environments/production/databases --body @payload.json
altertable api DELETE /service_accounts/sa_abc123
altertable api PATCH /environments/production/connections/conn_1 --body '{"name":"Renamed"}'Use --env <slug> to substitute {environment_id} in paths copied from api routes. Prefer full paths like /environments/production/... when the environment is known.
The method defaults to GET, switches to POST when request parameters or a body are provided, and can be overridden with -X/--method. Use -f/--raw-field for string parameters and -F/--field for typed values (true, false, null, integers, or @file). Forced GET and DELETE requests put fields in the query string; POST, PATCH, and PUT use fields as the JSON body unless --body/--input is supplied, in which case fields become query parameters.
For advanced or provider-specific payloads, pass raw JSON with --body or @file:
altertable api POST /environments/production/connections --body @postgres-connection.jsonInstall completion for bash, zsh, or fish:
altertable completion installThe CLI detects your shell from $SHELL, writes the completion script to the
standard user directory, and updates your shell startup file when bash or zsh
needs it. Open a new terminal, or reload your shell, to start using completion.
You can also choose a shell explicitly:
altertable completion install zsh
altertable completion install fishIf you need a manual install, generate the script without writing files:
# bash
altertable completion generate bash > ~/.local/share/bash-completion/completions/altertable
# zsh
altertable completion generate zsh > ~/.local/share/zsh/site-functions/_altertable
# fish
altertable completion generate fish > ~/.config/fish/completions/altertable.fishThe compatibility aliases altertable completion bash, altertable completion zsh, and
altertable completion fish also print raw scripts. Running altertable completion
in an interactive terminal opens a small menu; in non-interactive terminals it prints
usage guidance. Tab completion covers top-level commands, subcommands up to two levels deep, command-specific flags on leaf commands, and global flags (--json, --agent, --debug). Regenerate or reinstall scripts after upgrading the CLI.
These flags apply to every command and must be placed before the subcommand:
| Flag | Description |
|---|---|
--profile <name> |
Use a named profile for this invocation |
--json |
Output raw JSON (machine-readable success; JSON error envelope on stderr) |
--agent |
Agent preset: structured JSON output, no pager, colors, or terminal styling |
--debug, -d |
Enable debug output |
--connect-timeout <s> |
HTTP connect timeout in seconds (default: 5) |
--read-timeout <s> |
HTTP read timeout in seconds (default: 60; 0 = unlimited for streams) |
Per-request read timeout on query, upload, and upsert:
altertable query "SELECT ..." --read-timeout 180
altertable --read-timeout 120 query "SELECT ..."
altertable --connect-timeout 10 upload --catalog my_cat --schema public --table users --mode overwrite --format csv --file large.csv
altertable --connect-timeout 10 upsert --catalog my_cat --schema public --table users --primary-key id --format csv --file large.csvStream endpoints (lakehouse query streams) treat --read-timeout 0 as unlimited once connected.
Use --json or --agent for machine-readable output. On failure the error is a JSON object on stderr; stdout remains empty.
With --json, success stdout follows one of three contracts:
- Raw API — verbatim API response body (most
api *commands). - Normalized query —
{ metadata, columns, rows }fromquery --format json,query --json, oraltertable --agent query(stable scripting contract). - CLI envelope — CLI-shaped objects such as
{ catalogs: [...] }fromcatalogs list --json,{ profiles: [...] }fromprofile list --json, or{ cli_config, profile, details }fromprofile show --json.
Human mode defaults management list/get output to tables unless --format is set.
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Usage, validation, or unexpected CLI error |
2 |
Authentication failed (HTTP 401) |
3 |
Permission denied (HTTP 403) |
4 |
Not found (HTTP 404) |
5 |
Conflict (HTTP 409) |
6 |
Validation error (HTTP 422) |
7 |
Rate limited (HTTP 429) |
8 |
Server error (HTTP 5xx) |
9 |
Network or timeout error |
10 |
Configuration error (missing credentials) |
JSON error objects on stderr have the following fields: error (always true), code (stable snake_case identifier), message, exit_code, and optional details and status.
if ! out=$(altertable --json profile show 2>err.json); then
code=$(jq -r .exit_code err.json)
msg=$(jq -r .message err.json)
echo "Failed ($code): $msg" >&2
exit "$code"
fi
echo "$out" | jq .Without --json, errors are printed as [ERROR] … lines on stderr.
See DEVELOPMENT.md.
MIT