"Commands"
The Tether CLI handles project setup, migrations, and deployment.
Installation
npm install -g tthr
After installation, the tthr command is available globally.
Commands
tthr init <name>
Create a new Tether project: scaffold a framework app, install the Tether packages, create the project on Tether, and deploy a demo schema and functions.
tthr init my-app
# Skip the prompts
tthr init my-app --template nuxt --pm pnpm
# Accept the defaults for anything not passed
tthr init my-app --yes
| Option | Description |
|---|---|
-t, --template <framework> |
nuxt (or vue), next (or react), sveltekit (or svelte), or vanilla |
--pm <packageManager> |
npm, pnpm, yarn or bun |
-y, --yes |
Don't prompt. Use defaults for anything not passed as a flag |
-f, --force |
Replace the directory if it already exists and isn't empty |
Running without a terminal. In CI, scripts or AI agents, tthr init never waits for input. It behaves as if --yes was passed: the project name is required, the framework defaults to Nuxt, and the package manager defaults to the one that ran the CLI (for example pnpm dlx tthr init uses pnpm), falling back to npm.
Existing directories. An empty directory is used as is. A non-empty one is only replaced if you confirm the prompt or pass --force, and only after the new project has been fully set up, so a failed init never removes your files. The project is created on Tether only after the local setup succeeds.
Demo functions. The generated posts and comments functions use access: 'public' so the welcome page works straight away. Anyone who can reach your app can call them, so change them to authenticated once you add auth. See Access control.
tthr dev
Start the local development server with hot reloading.
tthr dev
# With specific port
tthr dev --port 3002
tthr generate
Generate TypeScript types from your schema.
tthr generate
Creates tether/_generated/db.ts and tether/_generated/api.ts.
tthr migrate system-columns
Rebuild tables made before Tether managed _id, _createdAt, _updatedAt and _deletedAt, so they use the system columns.
tthr migrate system-columns
# Another environment (default: development)
tthr migrate system-columns --env production
# Show what would change without changing anything
tthr migrate system-columns --dry-run
Schema changes don't need a migration command: tthr deploy applies your schema (the schema path in tether.config.ts) to the environment.
tthr deploy
Deploy schema and functions to Tether Cloud.
The target environment is resolved automatically from your TETHER_API_KEY in .env (e.g. a tthr_prod_* key deploys to production). You can override with -e:
tthr deploy
# Deploy schema only
tthr deploy --schema
# Deploy functions only
tthr deploy --functions
# Deploy to a specific environment
tthr deploy -e production
# Preview what would be deployed
tthr deploy --dry-run
# Deploy a schema with no tables, removing every table
tthr deploy --allow-destructive
A schema deploy applies completely or not at all. If the schema file has content but no tables the CLI can read, the deploy stops instead of removing every table; pass --allow-destructive only if that is what you want. Tables you remove from the schema are kept as __name while they still hold rows, and come back if you add them again.
Each deploy is recorded in the dashboard under Settings > Deployments, where you can redeploy an earlier version. See Deployment history and rollback.
tthr exec <sql>
Execute a SQL query directly against your project database.
tthr exec "SELECT * FROM users LIMIT 10"
# Check table schema
tthr exec "PRAGMA table_info(users)"
tthr update
Update all Tether packages to the latest version.
tthr update
# Preview changes without updating
tthr update --dry-run
tthr login
Authenticate with Tether Cloud.
tthr login
The CLI uses a device-code flow: it prints a URL and short code, you approve the device in the dashboard, and the CLI receives a Tether-issued session token stored in ~/.tether/credentials.json (permissions 0600).
The token only ever goes to the API it came from, over https (plain http only for a local server). If a project points the CLI at another API, through TETHER_API_URL or url in tether.config.ts, commands stop and ask you to log in to that server instead, so a cloned repository can't collect your login.
Session lifetime. CLI sessions are separate from dashboard (web) sessions and last much longer: a CLI token is valid for 90 days from last use (a sliding window). Any command that talks to the API silently extends the session (at most once every 24 hours), so a CLI you use regularly never expires. Web sessions are short-lived Strands Accounts tokens and are refreshed by the dashboard independently.
Expiry and revocation. If a token has expired, or has been revoked from the dashboard's Devices page, you are not left with a "please run tthr login" error. Instead the CLI signs you out and straight back in inline, in the middle of whatever command you ran, and once the device is approved it carries on with the original command (the failed request is replayed with the new token). The same happens if you run any authenticated command while not logged in at all.
In non-interactive shells (no TTY, or CI set) the CLI cannot open the login flow, so it exits with a message asking you to run tthr login.
tthr logout
Log out from Tether Cloud.
tthr logout
tthr whoami
Show the currently authenticated user and how long the current session has left if it goes unused.
tthr whoami