# Deployments

> Immutable snapshots of static files, each with its own URL: properties, lifecycle, limits, public deploys and claiming, passwords, labels and origin tags.

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

A deployment is an immutable snapshot of static files. Once created, its contents never change.

Every deployment gets a unique name (e.g. `happy-cat-abc1234`) and an instant preview URL. On every response the `deployment` field carries the full hostname — `happy-cat-abc1234.shipstatic.com` — which is the form every interface shows and accepts.

Available via [Web](https://docs.shipstatic.com/web), [CLI](https://docs.shipstatic.com/cli), [SDK](https://docs.shipstatic.com/sdk), [MCP](https://docs.shipstatic.com/mcp), [Action](https://docs.shipstatic.com/action), and [API](https://docs.shipstatic.com/api).

## Properties

| Property | Description |
|----------|-------------|
| `deployment` | Unique identifier — the deployment's hostname |
| `url` | Preview URL, immediately accessible |
| `files` | Number of files |
| `size` | Total size in bytes |
| `status` | Lifecycle state (see below) |
| `labels` | Mutable tags for organization |
| `password` | `true` if the deployment is password-protected |
| `via` | Origin tag — see [Origin tags](https://docs.shipstatic.com/deployments#origin-tags) below |
| `created` | Creation timestamp |
| `claim` | Claim URL — present only on response of public (unauthenticated) deploys |
| `expires` | Expiry as a unix timestamp in seconds. Set for deploys made without an account (3 days from creation) and for any deployment given a `ttl` |

## Status

```
pending → success → deleting
        → failed  → deleting
```

A deployment starts as `pending` during upload. On success, the preview URL goes live. Deletion is asynchronous from any terminal state — the status transitions to `deleting` while files are cleaned up.

## Behaviors

**Immutable.** After creation, only labels can be modified. To change content, create a new deployment.

**An `index.html` at the top.** Every deployment needs an `index.html` at the top: it's the page visitors see first. A deploy without one, or with an empty one, is refused, and the refusal says what to do: publish the folder that holds your `index.html` when it sits one folder down (like `dist/`), put your main page at the top and name it `index.html`, or, to publish a file on its own, like an image or a PDF, add a small `index.html` that links to it.

**Path optimization.** When all files share a common root directory (e.g. `dist/`), the platform flattens it automatically — `dist/index.html` becomes `index.html`.

**SPA detection.** A deployment whose only page is an `index.html` with no content of its own (a container and a script, which is what React, Vue, Angular, Svelte and similar builds produce) is treated as a single-page app, and every path is routed to `index.html` automatically. Anything else is served as its files. The CLI, the SDK and the integrations ask for this on every deploy; through the API, send `spa=true`. If your app needs the fallback and is not detected, add the rewrite yourself in [ship.json](https://docs.shipstatic.com/ship-json).

**robots.txt and favicon.ico.** If your site doesn't have a `robots.txt` at its root, we add one that lets every search engine crawl everything. If it doesn't have a `favicon.ico` at its root, we add ShipStatic's icon, which browsers show in the tab when your pages name no icon of their own. Both are real files in your deployment, so they count in `files` and `size`, but never against your file limits. If you upload your own, we use yours and add nothing.

## Limits

What one deployment may carry. These bound a **single publish** — they are not
account totals — and the API enforces them on every deploy, whichever interface
you use.

| | Free | Pro | Team |
|---|---|---|---|
| Largest single file | 20 MB | 50 MB | 50 MB |
| Files per deployment | 500 | 1,000 | 1,000 |
| Total deployment size | 50 MB | 200 MB | 200 MB |

Deploys made without an account use the Free limits. Scale is arranged directly
and its limits are higher. What each plan is for is under [Plans](https://docs.shipstatic.com/plans).

Your own current limits are always available from `GET /limits` ([API](https://docs.shipstatic.com/api)),
`ship.getLimits()` ([SDK](https://docs.shipstatic.com/sdk)), and the Plan page in the console ([Web](https://docs.shipstatic.com/web)). That
answer reflects your plan and any adjustment made on your account, so prefer it
to this table whenever the two could differ.

## Public Deployments

Deploys without authentication go to the public account and expire **3 days** from creation. 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.

```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
}
```

Once claimed, the deployment is yours and never expires. The claim URL then works for nobody else; opening it again yourself only shows you the deployment.

Until then, the claim URL is what transfers ownership, so anyone holding it can claim the deployment — share it the way you would a one-time invite rather than posting it somewhere public. Worth knowing if an agent prints one into a chat you keep around: the link stays usable for the same 3 days the deployment does. Claiming it yourself is what closes it.

The claim URL appears once, in the deploy response. The platform keeps only a hash of it, so nothing can show it again: whoever deploys on someone else's behalf, an agent included, hands it over straight away.

Custom domains, password rotation, and listing/management operations require an [API Key](https://docs.shipstatic.com/api-key). The deploy itself doesn't.

## Password Protection

Deployments can be locked behind a password set at upload time. Visitors see an unlock page until they enter the correct value. Passwords are stored securely — ShipStatic cannot reveal or recover one, so keep it somewhere safe.

Length: 6 to 128 characters. There is no edit-in-place — to change or remove a password, redeploy.

```bash
ship ./dist --password 'hunter2!'
```

## Labels

Labels organize deployments. A label is a word like `production`, or a key and a value split by one `:` like `env:production`. Each side is letters and numbers, with `.`, `-` or `_` between them. A label is 3 to 63 characters, and a deployment can have up to 10.

```
production
v1.0.3
env:production
team:web
```

Labels are stored in lowercase, so `Env:Prod` becomes `env:prod`. A deployment can have more than one value for the same key. A deployment uploaded with a [token](https://docs.shipstatic.com/tokens) also gets the token's labels, ahead of its own.

## Origin tags

The `via` field records which interface created the deployment, useful for filtering listings by origin.

| Value | Origin |
|-------|--------|
| `web` | [Web](https://docs.shipstatic.com/web) console (drag-drop or upload) |
| `cli` | [CLI](https://docs.shipstatic.com/cli) |
| `sdk` | [SDK](https://docs.shipstatic.com/sdk) used directly |
| `mcp` | [MCP](https://docs.shipstatic.com/mcp) server (AI agents) |
| `git` | [Action](https://docs.shipstatic.com/action) (GitHub Actions) |
| `n8n` | n8n community node |
| `gpt` | The ChatGPT plugin |
| `vsc` | [VS Code](https://docs.shipstatic.com/vs-code) extension |
| `cld` | The Claude connectors directory |
| `crs` | The Cursor marketplace |
| `gmn` | The Gemini CLI extension |
| `api` | A call straight to the [API](https://docs.shipstatic.com/api) that named no origin |

## Operations

| Operation | Description |
|-----------|-------------|
| Upload | Create a new deployment from files |
| List | All deployments on your account |
| Get | Details of a specific deployment |
| Set | Update labels |
| Delete | Delete a deployment and its files |
