# Environment variables

> Server: BLOB_READ_WRITE_TOKEN, BLOB_STORE_URL, VCUP_TOKEN, VCUP_BASE_URL. Client: VCUP_API_URL, VCUP_TOKEN, optional BLOB_STORE_URL for rm.

- 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

- `.env.example`
- `README.md`
- `cli.ts`
- `api/upload.ts`
- `api/f.ts`
- `api/delete.ts`

---

---
title: "Environment variables"
description: "Server: BLOB_READ_WRITE_TOKEN, BLOB_STORE_URL, VCUP_TOKEN, VCUP_BASE_URL. Client: VCUP_API_URL, VCUP_TOKEN, optional BLOB_STORE_URL for rm."
---

vcup splits configuration across a Vercel serverless deployment and the Bun CLI: server handlers read Blob and auth variables at runtime, while `cli.ts` resolves API endpoint and token from env or `~/.vcuprc`, with an optional client-only `BLOB_STORE_URL` when deleting by proxy URL.

## Variable map

| Variable | Runtime | Required | Used by |
| --- | --- | --- | --- |
| `BLOB_READ_WRITE_TOKEN` | Server (Vercel) | Yes | `@vercel/blob` `put` / `del` in `api/upload.ts`, `api/delete.ts` |
| `BLOB_STORE_URL` | Server | Yes for `/f` proxy | `api/f.ts` — reconstructs upstream blob URL |
| `BLOB_STORE_URL` | Client (CLI) | Only for `vcup rm` on proxy URLs | `cli.ts` — maps `/f/:slug` to raw blob URL |
| `VCUP_TOKEN` | Server | Yes for upload/delete | `api/upload.ts`, `api/delete.ts` — Bearer check |
| `VCUP_TOKEN` | Client | Yes* | `cli.ts` — `Authorization: Bearer` on upload/delete |
| `VCUP_BASE_URL` | Server | No | `api/upload.ts` — prefix for `url` in JSON response |
| `VCUP_API_URL` | Client | Yes* | `cli.ts` — base URL for `/api/upload` and `/api/delete` |
| `VCUP_API_URL` | — | — | Same value as `url` in `~/.vcuprc` |

\*Required unless `~/.vcuprc` supplies both `url` and `token`.

```text
  ┌──────────────────── Vercel deployment ────────────────────┐
  │ BLOB_READ_WRITE_TOKEN  →  @vercel/blob put/del           │
  │ BLOB_STORE_URL         →  api/f.ts fetch upstream        │
  │ VCUP_TOKEN             →  api/upload.ts, api/delete.ts   │
  │ VCUP_BASE_URL (opt.)   →  api/upload.ts response url     │
  └──────────────────────────────────────────────────────────┘
                              ▲ POST/DELETE + Bearer
                              │
  ┌──────────────────── CLI (cli.ts) ─────────────────────────┐
  │ VCUP_API_URL + VCUP_TOKEN  →  upload/delete requests     │
  │ BLOB_STORE_URL (opt.)      →  vcup rm on /f/... URLs     │
  └──────────────────────────────────────────────────────────┘
```

## Server variables

Set these on the Vercel project (or in a local `.env` for `vercel dev`). `.env.example` documents the three Blob/auth entries; `VCUP_BASE_URL` is optional and only appears in upload handler code.

### `BLOB_READ_WRITE_TOKEN`

Vercel Blob read/write credential from **Project Settings → Storage → Blob**. The handlers never read this name directly; `@vercel/blob` picks it up automatically for `put()` in `api/upload.ts` and `del()` in `api/delete.ts`.

<Note>
The one-click deploy button pre-wires `BLOB_READ_WRITE_TOKEN`, `BLOB_STORE_URL`, and `VCUP_TOKEN` in the clone URL. After deploy, confirm values in the dashboard match your Blob store.
</Note>

### `BLOB_STORE_URL`

Public base URL of the blob store (no trailing path), e.g. `https://abc123.public.blob.vercel-storage.com`.

- **`api/f.ts`**: Required. Builds `${BLOB_STORE_URL}/${slug}` to `fetch` the object. Missing config returns **500** with body `BLOB_STORE_URL not configured`.
- **Not used** by upload or delete handlers; upload returns the full `raw` URL from `put()`.

### `VCUP_TOKEN`

Shared secret for authenticated routes. Both upload and delete compare the `Authorization` header (Bearer token) to `process.env.VCUP_TOKEN`:

- Missing or empty server token → **401** `Unauthorized` for every request.
- Mismatch → **401** `Unauthorized`.

The CLI must use the **same** string in `VCUP_TOKEN` (env) or `token` in `~/.vcuprc`. Proxy GET `/f/:slug` does **not** check this token.

### `VCUP_BASE_URL`

Optional override for the **proxy** link returned from upload, not the raw blob URL.

When set, upload JSON uses:

`{ "url": "${VCUP_BASE_URL}/f/${slug}", "raw": "<blob.url from put>" }`

When unset, the handler derives the base from the incoming request:

`${x-forwarded-proto || "http"}://${host}`

Use this when the deployment hostname in responses should differ from the request host (custom domain, canonical HTTPS URL, or local dev behind a tunnel). It does not change where the CLI sends API traffic — that remains `VCUP_API_URL` / `~/.vcuprc` `url`.

## Client variables

The published CLI (`cli.ts`, bin `vcup`) runs on your machine with Bun.

### `VCUP_API_URL` and `VCUP_TOKEN`

`loadConfig()` resolution order:

1. If **both** `VCUP_API_URL` and `VCUP_TOKEN` are set → use env only (ignore `~/.vcuprc` for the missing half).
2. Else if `~/.vcuprc` exists → `url = VCUP_API_URL || rc.url`, `token = VCUP_TOKEN || rc.token`.
3. Else → exit **1** with a message to set env vars or create `~/.vcuprc`.

`VCUP_API_URL` is the deployment origin **without** a path suffix (e.g. `https://your-app.vercel.app`). The CLI appends `/api/upload` or `/api/delete`.

<ParamField body="VCUP_API_URL" type="string" required>
Deployment base URL. Equivalent to the `url` field in `~/.vcuprc`.
</ParamField>

<ParamField body="VCUP_TOKEN" type="string" required>
Must match server `VCUP_TOKEN`. Sent as `Authorization: Bearer …` on upload and delete.
</ParamField>

### `BLOB_STORE_URL` (CLI, optional)

Only required for:

```bash
vcup rm https://your-host/f/some-slug-with-suffix.png
```

If the argument contains `/f/`, the CLI extracts the slug and builds `${BLOB_STORE_URL}/${slug}` before calling `DELETE /api/delete` with header `X-Blob-Url`.

Without this variable, proxy deletes exit **1**:

`Cannot resolve proxy URL without BLOB_STORE_URL env var.`

<Tip>
Pass the **raw** blob URL from upload (`raw` field or `vcup --raw`) to delete without setting client `BLOB_STORE_URL`. The server `del()` accepts the full Vercel Blob URL directly.
</Tip>

Client `BLOB_STORE_URL` should match the server value (same public store base).

## Example layouts

<Tabs>
  <Tab title="Vercel production">
```bash
# Server (Vercel project env)
BLOB_READ_WRITE_TOKEN=vercel_blob_rw_...
BLOB_STORE_URL=https://xxxx.public.blob.vercel-storage.com
VCUP_TOKEN=your-long-random-secret
VCUP_BASE_URL=https://files.example.com   # optional
```
  </Tab>
  <Tab title="CLI shell">
```bash
export VCUP_API_URL=https://your-app.vercel.app
export VCUP_TOKEN=your-long-random-secret
export BLOB_STORE_URL=https://xxxx.public.blob.vercel-storage.com  # optional unless using vcup rm on /f/ URLs
```
  </Tab>
  <Tab title="Local vercel dev">
Copy `.env.example` to `.env` (gitignored), fill the three server vars, then `bun run dev` / `vercel dev`. Point the CLI at the dev origin with `VCUP_API_URL`.
  </Tab>
</Tabs>

## Which routes read which vars

| Route | Auth | Server env |
| --- | --- | --- |
| `POST /api/upload` | `VCUP_TOKEN` | `VCUP_TOKEN`, `BLOB_READ_WRITE_TOKEN` (SDK), optional `VCUP_BASE_URL` |
| `DELETE /api/delete` | `VCUP_TOKEN` | `VCUP_TOKEN`, `BLOB_READ_WRITE_TOKEN` (SDK) |
| `GET /f/:slug` → `api/f` | None | `BLOB_STORE_URL` |

## Failure signals

| Symptom | Likely cause |
| --- | --- |
| CLI: `Missing config` | No `VCUP_API_URL`/`VCUP_TOKEN` and no `~/.vcuprc` |
| Upload/delete **401** | `VCUP_TOKEN` mismatch or unset on server |
| Proxy **500** `BLOB_STORE_URL not configured` | Server `BLOB_STORE_URL` unset |
| Proxy **502** `Failed to fetch file` | Wrong store URL or slug; upstream fetch error |
| `vcup rm` on `/f/…` fails immediately | Client `BLOB_STORE_URL` unset |
| Proxy URL in upload JSON shows wrong host | Set `VCUP_BASE_URL` on server |

## Related pages

<CardGroup>
  <Card title="Configuration reference" href="/configuration-reference">
    ~/.vcuprc keys, precedence, and handler validation messages.
  </Card>
  <Card title="Deploy on Vercel" href="/deploy-vercel">
    Blob store creation and deploy-button env wiring.
  </Card>
  <Card title="Configure the CLI" href="/configure-cli">
    RC file vs env precedence for daily use.
  </Card>
  <Card title="Custom domain" href="/custom-domain">
    When to set VCUP_BASE_URL alongside ~/.vcuprc url.
  </Card>
  <Card title="Authentication" href="/authentication">
    Bearer token behavior on upload and delete.
  </Card>
  <Card title="Local development" href="/local-development">
    .env from .env.example and vercel dev workflow.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Status codes and config-related errors.
  </Card>
</CardGroup>
