# Quickstart

> Configure ~/.vcuprc or env vars, upload one file, verify the printed proxy URL opens inline, and optional --raw output.

- Repository: MaxLeiter/vcup
- GitHub: https://github.com/MaxLeiter/vcup
- Human docs: https://grok-wiki.com/public/docs/maxleiter-vcup-05c16ae77ebb
- Complete Markdown: https://grok-wiki.com/public/docs/maxleiter-vcup-05c16ae77ebb/llms-full.txt

## Source Files

- `README.md`
- `cli.ts`
- `api/upload.ts`
- `api/f.ts`

---

---
title: "Quickstart"
description: "Configure ~/.vcuprc or env vars, upload one file, verify the printed proxy URL opens inline, and optional --raw output."
---

The `vcup` CLI in `cli.ts` loads `VCUP_API_URL` and `VCUP_TOKEN` (or `~/.vcuprc`), streams a file to `POST /api/upload` with `Authorization: Bearer` and `X-Filename`, and prints the JSON `url` field—a proxy link under `/f/:slug` that `vercel.json` rewrites to `api/f.ts` for inline browser display. Use `--raw` to print the Vercel Blob URL from the `raw` field instead.

## Prerequisites

| Requirement | Notes |
| --- | --- |
| Deployed vcup instance | Vercel project with Blob store, `VCUP_TOKEN`, `BLOB_STORE_URL`, and `BLOB_READ_WRITE_TOKEN` set on the server. See [Deploy on Vercel](/deploy-vercel). |
| Matching client secret | The `token` in `~/.vcuprc` (or `VCUP_TOKEN` env) must equal the server `VCUP_TOKEN`. |
| CLI runtime | Global install uses Bun (`#!/usr/bin/env bun` in `cli.ts`). |

<Note>
This quickstart assumes a deployment already exists. If you need to create one first, follow [Deploy on Vercel](/deploy-vercel) before configuring the CLI.
</Note>

## Install the CLI

<Tabs>
  <Tab title="bun">
    ```bash
    bun install -g @maxleiter/vcup
    ```
  </Tab>
  <Tab title="npm">
    ```bash
    npm install -g @maxleiter/vcup
    ```
  </Tab>
</Tabs>

The published `vcup` bin maps to `cli.ts` (`package.json` → `"bin": { "vcup": "./cli.ts" }`).

## Configure the client

Point the CLI at your deployment API origin and shared upload secret.

<Steps>
  <Step title="Create ~/.vcuprc">
    ```json
    {
      "url": "https://your-vcup-deployment.vercel.app",
      "token": "your-vcup-token"
    }
    ```

    <ParamField body="url" type="string" required>
      Base URL of the vcup deployment (no trailing path). Used as `${url}/api/upload` and `${url}/api/delete`.
    </ParamField>

    <ParamField body="token" type="string" required>
      Shared secret; sent as `Authorization: Bearer &lt;token&gt;` on upload and delete.
    </ParamField>
  </Step>

  <Step title="Or set environment variables">
    <CodeGroup>
      ```bash title="Shell"
      export VCUP_API_URL="https://your-vcup-deployment.vercel.app"
      export VCUP_TOKEN="your-vcup-token"
      ```
    </CodeGroup>

    When **both** `VCUP_API_URL` and `VCUP_TOKEN` are set, `loadConfig()` returns them and does not read `~/.vcuprc`. If only one is set, the other can come from `~/.vcuprc` (`url || rc.url`, `token || rc.token`).
  </Step>

  <Step title="Confirm config loads">
    Run `vcup --help` with no file and a TTY stdin; missing config exits with a JSON example and status `1`.
  </Step>
</Steps>

<Warning>
Without `url` and `token`, upload fails before any network call: `Missing config. Set VCUP_API_URL and VCUP_TOKEN env vars, or create ~/.vcuprc`.
</Warning>

For precedence, partial overrides, and custom domains, see [Configure the CLI](/configure-cli) and [Custom domain](/custom-domain).

## Upload one file

```bash
vcup screenshot.png
```

Behavior:

- Resolves the path, rejects missing files and directories (`Cannot upload a directory`).
- Streams the body in 64KB chunks with a stderr progress bar.
- `POST` `${config.url}/api/upload` with headers `Authorization: Bearer ${token}` and `X-Filename: ${basename}`.

<ResponseExample>
```json
{
  "url": "https://your-vcup-deployment.vercel.app/f/myfile-abc123.png",
  "raw": "https://abc123.public.blob.vercel-storage.com/myfile-abc123.png"
}
```
</ResponseExample>

On success the CLI prints **one line** to stdout: `data.url` by default.

```mermaid
sequenceDiagram
  participant CLI as cli.ts
  participant API as api/upload.ts
  participant Blob as Vercel Blob

  CLI->>API: POST /api/upload<br/>Bearer + X-Filename + stream
  API->>API: Validate VCUP_TOKEN
  API->>Blob: put(filename, stream, public, random suffix)
  Blob-->>API: blob.url
  API->>API: slug = pathname; baseUrl from VCUP_BASE_URL or Host
  API-->>CLI: 200 { url: baseUrl/f/slug, raw: blob.url }
  CLI-->>CLI: stdout: url (or raw if --raw)
```

## Verify the proxy URL

1. Copy the printed `url` (path `/f/...`).
2. Open it in a browser or `curl -I` the URL.

The rewrite `{ "source": "/f/:slug*", "destination": "/api/f" }` routes to `api/f.ts`, which fetches `${BLOB_STORE_URL}/${slug}` and responds with:

| Header | Value |
| --- | --- |
| `Content-Type` | From `mime-types` lookup on the filename, else `application/octet-stream` |
| `Content-Disposition` | `inline` |
| `Cache-Control` | `public, max-age=31536000, immutable` |

<Check>
Inline display: images and PDFs should render in the browser tab rather than forcing a download, because `Content-Disposition` is `inline`.
</Check>

If the server lacks `BLOB_STORE_URL`, the proxy returns `500` with body `BLOB_STORE_URL not configured`. Missing slugs yield upstream `404` as `Not found`.

## Optional: print the raw blob URL

```bash
vcup --raw screenshot.png
```

The CLI still uploads the same way; stdout prints `data.raw` (the direct Vercel Blob URL from `put()`), not the `/f/` proxy link. Use this when integrating with tools that need the store URL, or for [Upload and delete](/upload-and-delete) flows that pass raw URLs to `vcup rm`.

<Info>
Server-side `VCUP_BASE_URL` overrides the host used in `url` in the upload JSON (for example a custom domain). It does not change what `--raw` prints.
</Info>

## Stdin upload (optional)

```bash
echo "hello world" | vcup
```

With no file argument and non-TTY stdin, the CLI reads all stdin, uses filename `paste.txt`, and prints the same `url` or `raw` line.

## Common failures (quickstart)

| Symptom | Likely cause |
| --- | --- |
| `Missing config` on first upload | No `~/.vcuprc` and incomplete env vars |
| `Upload failed: 401` | Client `token` ≠ server `VCUP_TOKEN` |
| `Upload failed: 400` | Missing `X-Filename` (should not happen from CLI) |
| Proxy `500 BLOB_STORE_URL not configured` | Server env not set after deploy |
| Proxy `502 Failed to fetch file` | Upstream fetch to blob store failed |

See [Troubleshooting](/troubleshooting) for full status codes and delete-path errors.

## Minimal command reference

| Command | Output |
| --- | --- |
| `vcup <file>` | Proxy URL (`url`) |
| `vcup --raw <file>` | Blob store URL (`raw`) |
| `echo "text" \| vcup` | Proxy URL for `paste.txt` |
| `vcup --help` | Usage and config hint |

Delete and progress-bar details: [Upload and delete](/upload-and-delete). Full flags and headers: [CLI reference](/cli-reference).

## Related pages

<CardGroup>
  <Card title="Installation" href="/installation">
    Global install with bun or npm and how the `vcup` bin maps to `cli.ts`.
  </Card>
  <Card title="Configure the CLI" href="/configure-cli">
    `~/.vcuprc` schema, env precedence, and matching a deployed instance.
  </Card>
  <Card title="Proxy and raw URLs" href="/proxy-and-raw-urls">
    `url` vs `raw`, `/f` rewrite, and inline `Content-Disposition`.
  </Card>
  <Card title="Deploy on Vercel" href="/deploy-vercel">
    Blob store, server env vars, and first deployment.
  </Card>
  <Card title="How vcup works" href="/how-it-works">
    End-to-end upload, proxy, and delete flow.
  </Card>
</CardGroup>
