# tus (/docs/adapters/tus)



[tus](https://tus.io) is an open protocol for resumable uploads, supported by tusd,
`@tus/server`, Supabase Storage, Cloudflare Stream, Vimeo and others. UploadCN wraps
the reference client, `tus-js-client`, rather than reimplementing the protocol.

<CodeBlockTabs defaultValue="npm">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npm install tus-js-client
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm add tus-js-client
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn add tus-js-client
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun add tus-js-client
    ```
  </CodeBlockTab>
</CodeBlockTabs>

```ts
import { tusAdapter } from "@uploadcn/core/tus"

const adapter = tusAdapter({
  endpoint: "https://tusd.example.com/files/",
  chunkSize: 8 * 1024 * 1024,
  headers: async () => ({ authorization: `Bearer ${await getToken()}` }),
  metadata: { bucket: "videos" },
})
```

The engine stores the tus upload URL as resume state, so it works with
[IndexedDB persistence](/docs/guides/resumable-uploads) across reloads (tus-js-client's
own localStorage fingerprinting is turned off). Cancelling an upload sends a tus
termination request.

<TypeTable
  type="{
  endpoint: { type: &#x22;string&#x22;, required: true },
  chunkSize: { type: &#x22;number&#x22;, description: &#x22;Bytes per PATCH request.&#x22; },
  parallelUploads: { type: &#x22;number&#x22;, description: &#x22;Requires the concatenation extension on the server.&#x22; },
  retryDelays: { type: &#x22;number[]&#x22;, default: &#x22;[]&#x22;, description: &#x22;tus-js-client's own retries. Off by default: the engine retries.&#x22; },
  headers: { type: &#x22;Record<string, string> | () => Promise<Record<string, string>>&#x22; },
  metadata: { type: &#x22;Record<string, string>&#x22;, description: &#x22;filename and filetype are always sent.&#x22; },
}"
/>
