> ## Documentation Index
> Fetch the complete documentation index at: https://upstash-dx-2982-blob-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Types

The option and record types the rest of these docs refer to, and the upload phases named in error messages.

***

## Size

```ts theme={"system"}
maxSize: 4096       // 4,096 bytes
maxSize: "20mb"     // 20,000,000 bytes
multipart: "100mb"
```

A byte count. A bare number is bytes; a string takes a unit: `b`, `kb`, `mb`, `gb`, `tb`.

Sizes are **decimal**, matching how storage is billed. `'2mb'` is 2,000,000 bytes, not 2,097,152. Binary spellings like `'5mib'` throw. An unparseable size throws a `TypeError` where the option is written, not per request.

A limit you write by hand takes a `Size`: `maxSize`, `multipart`. A measurement you forward is a plain `number` of bytes: the `size` option on `put`, and every `size` the SDK returns. That mirrors `File.size` and `Blob.size`, so a value flows from one to the other without conversion.

`formatBytes`, exported from all three entrypoints, formats a number the same decimal way: `formatBytes(2_400_000)` is `2.4 MB`.

***

## Duration

```ts theme={"system"}
expiresIn: 900       // 15 minutes
expiresIn: "15m"
olderThan: "7d"
cache: "1h"
```

A span of time. A bare number is **seconds**; a string takes a unit: `ms`, `s`, `m`, `h`, `d`, or a long form (`sec`, `seconds`, `min`, `minutes`, `hr`, `hours`, `day`, `days`). A string with no unit is seconds. An unparseable duration throws a `TypeError` naming the option.

***

## CacheOption

```ts theme={"system"}
cache: "immutable"
cache: "revalidate"
cache: "no-store"
cache: "15m"
cache: "public, max-age=60, s-maxage=31536000"
```

One of three words, a `Duration`, or a raw `Cache-Control` header. The header each one stores is on [Caching](/blob/bucket/caching#the-cache-option).

***

## Records

Four record shapes come back from the SDK. They nest.

| Type            | Fields                                                        | Returned by                                            |
| --------------- | ------------------------------------------------------------- | ------------------------------------------------------ |
| `BlobObject`    | `path`, `url?`, `versionedUrl?`, `size`, `etag`, `uploadedAt` | `list()`, `copy()`, `move()`, `updateJson()`           |
| `CompletedBlob` | `BlobObject` plus `contentType`                               | `put()`, `onUploadComplete`, a finished browser upload |
| `BlobInfo`      | `BlobObject` plus `contentType` and `metadata`                | `info()`                                               |
| `BlobDownload`  | `BlobInfo` plus `body: ReadableStream<Uint8Array>`            | `get()`                                                |

`BlobObject` fields:

| Field          | Type                  | Description                                                          |
| -------------- | --------------------- | -------------------------------------------------------------------- |
| `path`         | `string`              | The object's key.                                                    |
| `url`          | `string \| undefined` | The public object URL. `undefined` on a private bucket.              |
| `versionedUrl` | `string \| undefined` | `${url}?v=${etag}`, etag percent-encoded. `undefined` when `url` is. |
| `size`         | `number`              | Bytes.                                                               |
| `etag`         | `string`              | Storage's etag, quoted: `"9f3c..."`.                                 |
| `uploadedAt`   | `Date`                | Last modified.                                                       |

Across the SDK, `blob` names a record, never the bytes. Bytes go in and come out as `body`.

***

## Upload phases

A direct browser upload makes up to four kinds of request to your upload route. The names appear in error messages and across these docs.

| Phase    | When                      | What your route does                                                              |
| -------- | ------------------------- | --------------------------------------------------------------------------------- |
| `begin`  | First request, once       | Checks constraints, runs `onBeforeUpload`, signs the first URL(s). Never retried. |
| `parts`  | Multipart only, as needed | Signs the next batch of part URLs.                                                |
| `end`    | Once the bytes landed     | Completes the upload, runs `onUploadComplete`. Retried by the browser on failure. |
| `cancel` | On `cancel()`             | Aborts the multipart upload, or deletes the single-PUT object.                    |

The PUTs that carry the bytes go to storage, never to your route. [How signing works](/blob/reference/signing#the-direct-upload-handshake) has the full handshake.
