---
title: CLI
description: Install linkdash-cli from npm, then run the `linkdash` command. Successful commands print JSON on stdout. Help and errors are plain text on stderr.
sidebar:
  label: CLI
  order: 3
---

```bash
npm i -g linkdash-cli
# or: pnpm add -g linkdash-cli / bun add -g linkdash-cli / npx linkdash-cli@latest
```

The npm package is `linkdash-cli`. The command is `linkdash`.

HTTP equivalent: [HTTP API](/api). MCP: [MCP](/mcp). Agent skill: [Agent skill](/skill). Pricing: [Pricing](/pricing). Plain markdown: [cli.md](https://linkdash.dev/cli.md).

There is no `--json` flag. Exit code 1 on errors.

## Auth

```bash
linkdash auth create
linkdash auth login
linkdash auth whoami
linkdash auth logout
```

No account yet? `auth create` opens https://linkdash.dev/sign-up, then returns to https://linkdash.dev/device with the CLI code so you can approve. Already have an account? `auth login` opens `/device`. Headless: set `LINKDASH_TOKEN` to a session token from `auth create` or `auth login`. Do not invent tokens.

Session file: `~/.config/linkdash/config.json` (mode 0600).

The CLI cannot change email, password, or billing. Send the user to the [dashboard](https://linkdash.dev/dashboard/billing). API keys (HTTP and MCP): [API keys](https://linkdash.dev/dashboard/keys).

## Commands

```
linkdash <command> [options]
```

| Command | What it does |
| --- | --- |
| `auth create` | Browser sign-up, then device approval |
| `auth login` | Browser device login |
| `auth logout` | Forget the stored session |
| `auth whoami` | Signed-in account JSON |
| `links list` | List links |
| `links get <id>` | One link |
| `links create --url <url>` | Short link from a URL |
| `links create --file <path>` | Upload a file and get a link |
| `links create --text <text>` | Store a snippet |
| `links update <id>` | Change destination, file, password, expiry, domain, or status |
| `links delete <id>` | Delete a link |
| `links stats <id>` | Visit, download, and play totals |
| `links export` | Print all links as CSV |
| `links import <file>` | Import URL rows from CSV |
| `webhooks list` | List webhook endpoints (secret masked) |
| `webhooks get <id>` | Show one webhook URL (secret masked) |
| `webhooks create --url <https>` | Add an HTTPS endpoint (secret shown once) |
| `webhooks rotate <id>` | Issue a new signing secret |
| `webhooks delete <id>` | Remove a webhook |
| `domains list` | List custom hostnames |
| `domains add <host>` | Add a hostname (1 on Free) |
| `domains connect <host>` | Domain Connect apply URL, or null |
| `domains verify <host>` | Check DNS with Unkey |
| `domains remove <host>` | Remove a hostname |
| `-h, --help` | Help (plain text) |
| `-v, --version` | Version |

If the same slug exists on two of the owner’s domains, pass `--domain`.

## Create and update flags

Slug is the public path. Name is only visible to you. Create takes **exactly one** of `--url`, `--file`, or `--text`.

| Flag | Notes |
| --- | --- |
| `--url <url>` | Destination URL |
| `--file <path>` | File to upload (create, or replace bytes on update) |
| `--text <text>` | Snippet |
| `--slug <id>` | Public path: `a-z0-9` and internal hyphens, 1–64 |
| `--name <label>` | Private label |
| `--tag <tag>` | Repeatable. Lowercase, no commas. Max 20 |
| `--starts <when>` | Go live after `7d`, `24h`, `30m`, or an ISO date |
| `--password <secret>` | Require this password to open |
| `--expires <when>` | Stop serving after `7d`, `24h`, `30m`, or an ISO date |
| `--max-openings <n>` | Pause after this many openings. Omit for unlimited |
| `--domain <host>` | Serve on this host instead of `lida.sh` |
| `--status <active\|paused>` | Pause or resume (update only) |
| `--preview-name <text>` | Public unfurl name |
| `--preview-description <text>` | Public unfurl description |
| `--preview-image <path>` | Public unfurl image |
| `--utm-source` `--utm-medium` `--utm-campaign` `--utm-term` `--utm-content` | URL links only |
| `--clear-password` `--clear-expires` `--clear-starts` `--clear-tags` `--clear-preview` `--clear-name` `--clear-max-openings` | Update only |

`--status` only accepts `active` or `paused`. Expired comes from `--expires`. Scheduled comes from `--starts`. Public resolve is not-found until start. After `--max-openings` is reached the link pauses; raise the number, or `--clear-max-openings`, to serve it again. Openings already used stay counted until you change or remove the limit.

`lida.sh` slugs are shared. If a word is taken, add a [custom domain](/domains) and retry with `--domain`. A branded-domain link does not also publish on `lida.sh`.

## List flags

| Flag | Notes |
| --- | --- |
| `--q <text>` | Search name, slug, target, and tags |
| `--tag <tag>` | Filter by tag |
| `--kind <url\|file\|text>` | Filter by kind |
| `--status <status>` | `active`, `paused`, `expired`, or `scheduled` |

## Stats

```bash
linkdash links stats <id> --last 24h
```

`--last` is a duration (`24h`, `7d`). Default `24h`. JSON includes `visits`, `downloads`, `plays`, `visitsInLast`, `countries`, `referrers`, and `visitors`.

## CSV

Columns: `slug,kind,name,url,text,fileName,status,domain,tags,starts,expires,maxOpenings,created`. No passwords.

```bash
linkdash links export > links.csv
linkdash links import links.csv
```

Import creates or updates URL (and text) rows by slug. File rows without bytes are skipped with a per-row error.

## Examples

```bash
linkdash links create --url https://example.com/q4/deck.pdf --slug deck --name "Q4 deck"
linkdash links create --file ./deck.pdf --expires 7d --starts 1d
linkdash links create --url https://example.com --max-openings 1
linkdash links update k3m9xq --max-openings 5
linkdash links update k3m9xq --clear-max-openings
linkdash links create --text "release checklist" --tag launch --tag q4
linkdash links list --q deck --tag launch --kind file --status paused
linkdash links get welcome --domain go.example.com
linkdash links update deck --file ./new.pdf
linkdash links update k3m9xq --status paused
```

See also [webhooks](/webhooks) and [custom domains](/domains).
