# CLI

> Publish from a terminal, or from any agent that can run one, with a single npx command and no account, then manage deployments, domains and tokens.

Source: https://docs.shipstatic.com/cli

Put a site online with one command — nothing to install, and no account needed. [NPM](https://www.npmjs.com/package/@shipstatic/ship) / [GIT](https://github.com/shipstatic/ship)

## Quick Start

Zero install — deploy in one line:

```bash
npx -y @shipstatic/ship ./dist
```

Or install once and use repeatedly:

```bash
npm install -g @shipstatic/ship
ship ./dist
```

Your site is live in seconds.

## Deploying without an account

No sign-up, no key, nothing to configure — the command above works in a fresh shell. Deployments made this way are public and expire in 3 days. The response includes a `claim` URL — visit it while signed in at [my.shipstatic.com](https://my.shipstatic.com) to transfer the deployment to your account and keep it permanently.

```bash
$ npx -y @shipstatic/ship ./dist --json
{
  "deployment": "happy-cat-abc1234.shipstatic.com",
  "url": "https://happy-cat-abc1234.shipstatic.com",
  "claim": "https://my.shipstatic.com/claim/...",
  "expires": 1755302400
}
```

A failure is JSON too, on stderr, and the exit code is non-zero: the same `error` tag and `status` the API answers, listed under [its errors](https://docs.shipstatic.com/api#errors). Branch on those, never on the message text.

## Deploy to your account

**Deploying needs no account.** Everything else — listing, custom domains, account operations — needs a credential: pass an [API Key](https://docs.shipstatic.com/api-key) (or a [deploy token](https://docs.shipstatic.com/tokens)) via flag, environment variable, or config file.

**Your API key goes wherever a `token` is asked for.** One credential, two names — the console mints it as an *API key* (`ship-…`), and every slot that carries it is called the *token*: `--token`, `SHIP_TOKEN`, and the `token` key in `~/.shiprc`. Paste the same value into any of them.

## Commands

### Deploy (shortcut)

```bash
ship <path>
ship <path> --domain www.example.com      # Deploy and serve it there
ship <path> --label production --label v1.0
ship <path> --password 'hunter2!'
ship <path> --ttl 7d                      # Expires in a week
ship <path> --no-spa-detect --no-path-detect
```

### Deployments

```bash
ship deployments upload <path>
ship deployments list
ship deployments get <deployment>
ship deployments set <deployment> --label production
ship deployments delete <deployment>
```

### Domains

```bash
ship domains set <name>                   # Reserve
ship domains set <name> <deployment>      # Link or switch
ship domains set <name> --label prod      # Label
ship domains list
ship domains get <name>
ship domains validate <name>              # Pre-flight check
ship domains verify <name>                # Trigger DNS verification
ship domains records <name>               # Required DNS records
ship domains dns <name>                   # Look up the domain's DNS provider
ship domains share <name>                 # Shareable DNS setup link
ship domains delete <name>
```

### Tokens

```bash
ship tokens create --ttl 30d --label ci   # Or 3600, 90s, 1h — one grammar
ship tokens list
ship tokens get <token>
ship tokens delete <token>
```

`ship tokens create -q` prints the token **secret** — it is shown once and never again, which is why that channel exists (`ship tokens create -q >> .env`). Every other `-q` prints the identifier.

### Account

```bash
ship whoami                               # Current account
ship account get                          # Same as whoami
ship ping                                 # API connectivity
```

### Setup

```bash
ship config                               # Interactive ~/.shiprc setup
ship completion install                   # Install shell completions (bash, zsh, fish)
ship completion uninstall                 # Remove shell completions
```

## Global Flags

Apply to every command.

| Flag | Description |
|------|-------------|
| `--token <token>` | Any ship token: API key (`ship-…`) or deploy token (`deploy-…`) |
| `--api-url <url>` | API URL (for development) |
| `--config <file>` | Custom config file path |
| `--json` | JSON output: the result on stdout, or the error on stderr with a non-zero exit code |
| `-q, --quiet` | Output only the resource identifier (compose with pipes) |
| `--no-color` | Disable colored output |
| `--help` | Show help |
| `--version` | Show version |

## Deploy Flags

Apply to `ship <path>` and `ship deployments upload`.

| Flag | Description |
|------|-------------|
| `--domain <domain>` | Serve this deployment at that domain — created or repointed. Requires a credential |
| `--label <label>` | Add label (repeatable) |
| `--password <pwd>` | Protect the deployment with a password (6–128 characters) |
| `--ttl <duration>` | Expire the deployment after that long — `3600`, `90s`, `30m`, `1h`, `7d`. Requires a credential; cannot be combined with `--domain` |
| `--no-path-detect` | Disable path optimization |
| `--no-spa-detect` | Disable SPA detection |

## Pagination

`deployments list`, `domains list` and `tokens list` return one page at a time.

| Flag | Description |
|------|-------------|
| `--limit <count>` | Maximum results per page |
| `--cursor <cursor>` | Continue from a previous page's cursor |

Text output prints a rerun hint when more pages exist; `--json` carries the
next `cursor` on the response.

```bash
ship deployments list --limit 20
ship deployments list --cursor <cursor>
```

## Deployments that expire

`--ttl` asks the platform to reclaim the deployment after a given time — a preview that cleans itself up rather than accumulating in your account:

```bash
ship ./dist --ttl 1h
ship ./dist --ttl 7d
ship ./dist --ttl 3600                    # bare seconds work too
```

Seconds, or a `<n><unit>` duration where the unit is `s`, `m`, `h` or `d` — the same grammar [`ship tokens create --ttl`](https://docs.shipstatic.com/tokens) uses. The maximum is one year.

The response's `expires` is the answer, in unix seconds. The platform stamps it from its own clock, so the lifetime is exactly as long as you asked for regardless of how your machine's clock is set.

Two things it will not do, both refused before anything uploads:

- **It requires a credential.** An anonymous deployment already expires in 3 days on the platform's own schedule, so there is no deployer to choose a different lifetime.
- **It cannot be combined with `--domain`.** A domain is a commitment and a deadline is its opposite — the platform refuses to point a domain at a deployment that is going to be reclaimed.

There is no way to extend or shorten a deployment once it exists. To keep something longer, deploy it again.

## Deploy and serve, in one command

`--domain` deploys and then points that domain at the result — creating the domain if it is new, repointing it if it already exists. It answers as the **domain**, exactly as [`ship domains set`](https://docs.shipstatic.com/domains) does, including the DNS records and setup link on a new external domain:

```bash
ship ./dist --domain www.example.com
```

It requires a credential — an anonymous account cannot own a domain — and refuses before uploading anything if there isn't one. If the link fails, the deployment still exists and is reported first; re-running links it again.

## Composability

`-q` outputs only the identifier so you can pipe between commands:

```bash
ship ./dist -q | ship domains set www.example.com
```

The pipe and `--domain` are the same two API calls, and both are supported. Pipe when you are composing interactively; use `--domain` in CI, where one process means one exit code and one JSON document — a `run:` block is `bash -e` without `pipefail`, so a pipeline reports only the last command's status and a failed deploy is masked.

`--json` returns the full structured response — useful for scripts:

```bash
URL=$(ship ./dist --json | jq -r '.url')
```

## Configuration

Resolved in order of precedence:

1. Command-line flags
2. Environment variables (`SHIP_TOKEN`, `SHIP_API_URL`, `SHIP_PASSWORD`)
3. `~/.shiprc`

`SHIP_TOKEN` and the file's `token` key both hold your [API Key](https://docs.shipstatic.com/api-key) — or a [deploy token](https://docs.shipstatic.com/tokens), since one slot takes either.

Run `ship config` to write `~/.shiprc` interactively — it prompts for the token and saves it owner-only (`0600`), like `~/.netrc`. It is interactive by design: `--json` is refused rather than silently doing something else.

`--config <file>` reads and writes any path you name instead of `~/.shiprc`, which is how per-environment configs work:

```bash
ship --config dev.shiprc ./dist
```

The file is strict JSON with two keys, `token` and `apiUrl`; an empty file means "no config".

**No repository file is ever read.** A `.shiprc` or `package.json` `"ship"` key in your working directory is ignored — cloning a repository can never change which account you deploy to, or which host your credential is sent to.

`SHIP_PASSWORD` is a CLI-only convenience for `--password` (e.g. CI secrets). Empty values are treated as unset — an unset CI secret never accidentally protects a deploy.
