---
title: Resumable and large files (tus) · Cloudflare Stream docs
description: If you have a video over 200 MB, we recommend using the tus
  protocol for resumable file uploads. A resumable upload ensures that the
  upload can be interrupted and resumed without uploading the previous data
  again.
lastUpdated: 2025-05-16T16:37:37.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/stream/uploading-videos/resumable-uploads/
  md: https://developers.cloudflare.com/stream/uploading-videos/resumable-uploads/index.md
---

If you have a video over 200 MB, we recommend using the [tus protocol](https://tus.io/) for resumable file uploads. A resumable upload ensures that the upload can be interrupted and resumed without uploading the previous data again.

## Requirements

* Resumable uploads require a minimum chunk size of 5,242,880 bytes unless the entire file is less than this amount. For better performance when the client connection is expected to be reliable, increase the chunk size to 52,428,800 bytes.
* Maximum chunk size is 209,715,200 bytes.
* Chunk size must be divisible by 256 KiB (256x1024 bytes). Round your chunk size to the nearest multiple of 256 KiB. Note that the final chunk of an upload that fits within a single chunk is exempt from this requirement.

## Prerequisites

Before you can upload a video using tus, you will need to download a tus client.

For more information, refer to the [tus Python client](https://github.com/tus/tus-py-client) which is available through pip, Python's package manager.

```python
pip install -U tus.py
```

## Upload a video using tus

```sh
tus-upload --chunk-size 52428800 --header \
Authorization "Bearer <API_TOKEN>"
<PATH_TO_VIDEO> https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/stream
```

```sh
INFO Creating file endpoint
INFO Created: https://api.cloudflare.com/client/v4/accounts/d467d4f0fcbcd9791b613bc3a9599cdc/stream/dd5d531a12de0c724bd1275a3b2bc9c6
...
```

### Golang example

Before you begin, import a tus client such as [go-tus](https://github.com/eventials/go-tus) to upload from your Go applications.

The `go-tus` library does not return the response headers to the calling function, which makes it difficult to read the video ID from the `stream-media-id` header. As a workaround, create a [Direct Creator Upload](https://developers.cloudflare.com/stream/uploading-videos/direct-creator-uploads/) link. That API response will include the TUS endpoint as well as the video ID. Setting a Creator ID is not required.

```go
package main


import (
  "net/http"
  "os"


  tus "github.com/eventials/go-tus"
)


func main() {
  accountID := "<ACCOUNT_ID>"


  f, err := os.Open("videofile.mp4")


  if err != nil {
    panic(err)
  }


  defer f.Close()


  headers := make(http.Header)
  headers.Add("Authorization", "Bearer <API_TOKEN>")


  config := &tus.Config{
    ChunkSize:           50 * 1024 * 1024, // Required a minimum chunk size of 5 MB, here we use 50 MB.
    Resume:              false,
    OverridePatchMethod: false,
    Store:               nil,
    Header:              headers,
    HttpClient:          nil,
  }


  client, _ := tus.NewClient("https://api.cloudflare.com/client/v4/accounts/"+ accountID +"/stream", config)


  upload, _ := tus.NewUploadFromFile(f)


  uploader, _ := client.CreateUpload(upload)


  uploader.Upload()
}
```

You can also get the progress of the upload if you are running the upload in a goroutine.

```go
// returns the progress percentage.
upload.Progress()


// returns whether or not the upload is complete.
upload.Finished()
```

Refer to [go-tus](https://github.com/eventials/go-tus) for functionality such as resuming uploads.

### Node.js example

Before you begin, install the tus-js-client.

* npm

  ```sh
  npm i tus-js-client
  ```

* yarn

  ```sh
  yarn add tus-js-client
  ```

* pnpm

  ```sh
  pnpm add tus-js-client
  ```

Create an `index.js` file and configure:

* The API endpoint with your Cloudflare Account ID.
* The request headers to include an API token.

```js
var fs = require("fs");
var tus = require("tus-js-client");


// Specify location of file you would like to upload below
var path = __dirname + "/test.mp4";
var file = fs.createReadStream(path);
var size = fs.statSync(path).size;
var mediaId = "";


var options = {
  endpoint: "https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/stream",
  headers: {
    Authorization: "Bearer <API_TOKEN>",
  },
  chunkSize: 50 * 1024 * 1024, // Required a minimum chunk size of 5 MB. Here we use 50 MB.
  retryDelays: [0, 3000, 5000, 10000, 20000], // Indicates to tus-js-client the delays after which it will retry if the upload fails.
  metadata: {
    name: "test.mp4",
    filetype: "video/mp4",
    // Optional if you want to include a watermark
    // watermark: '<WATERMARK_UID>',
  },
  uploadSize: size,
  onError: function (error) {
    throw error;
  },
  onProgress: function (bytesUploaded, bytesTotal) {
    var percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
    console.log(bytesUploaded, bytesTotal, percentage + "%");
  },
  onSuccess: function () {
    console.log("Upload finished");
  },
  onAfterResponse: function (req, res) {
    return new Promise((resolve) => {
      var mediaIdHeader = res.getHeader("stream-media-id");
      if (mediaIdHeader) {
        mediaId = mediaIdHeader;
      }
      resolve();
    });
  },
};


var upload = new tus.Upload(file, options);
upload.start();
```

## Specify upload options

The tus protocol allows you to add optional parameters in the [`Upload-Metadata` header](https://tus.io/protocols/resumable-upload.html#upload-metadata).

### Supported options in `Upload-Metadata`

Setting arbitrary metadata values in the `Upload-Metadata` header sets values in the [meta key in Stream API](https://developers.cloudflare.com/api/resources/stream/methods/list/).

* `name`

  * Setting this key will set `meta.name` in the API and display the value as the name of the video in the dashboard.

* `requiresignedurls`

  * If this key is present, the video playback for this video will be required to use signed URLs after upload.

* `scheduleddeletion`

  * Specifies a date and time when a video will be deleted. After a video is deleted, it is no longer viewable and no longer counts towards storage for billing. The specified date and time cannot be earlier than 30 days or later than 1,096 days from the video's created timestamp.

* `allowedorigins`

  * An array of strings listing origins allowed to display the video. This will set the [allowed origins setting](https://developers.cloudflare.com/stream/viewing-videos/securing-your-stream/#security-considerations) for the video.

* `thumbnailtimestamppct`

  * Specify the default thumbnail [timestamp percentage](https://developers.cloudflare.com/stream/viewing-videos/displaying-thumbnails/). Note that percentage is a floating point value between 0.0 and 1.0.

* `watermark`

  * The watermark profile UID.

## Set creator property

Setting a creator value in the `Upload-Creator` header can be used to identify the creator of the video content, linking the way you identify your users or creators to videos in your Stream account.

For examples of how to set and modify the creator ID, refer to [Associate videos with creators](https://developers.cloudflare.com/stream/manage-video-library/creator-id/).

## Get the video ID when using tus

When an initial tus request is made, Stream responds with a URL in the `Location` header. While this URL may contain the video ID, it is not recommend to parse this URL to get the ID.

Instead, you should use the `stream-media-id` HTTP header in the response to retrieve the video ID.

For example, a request made to `https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/stream` with the tus protocol will contain a HTTP header like the following:

```plaintext
stream-media-id: cab807e0c477d01baq20f66c3d1dfc26cf
```
