Skip to content

Large File Uploads ​

Chunking is the advanced upload path for files that should not be sent in one request. When enabled, useCourier splits a large file into smaller pieces and sends those pieces sequentially to your chunk endpoint.

When chunking starts ​

Chunking is enabled with the fileChunking option. A file is chunked only when its size is greater than threshold.

tsx
import { useCourier } from "use-courier";

const { addFile } = useCourier({
  url: "/api/uploads",
  fileChunking: {
    route: "/api/uploads/chunks",
    threshold: 10 * 1024 * 1024,
    chunkSize: 5 * 1024 * 1024,
    maxChunkRetries: 2,
  },
});
ts
import { useCourier } from "use-courier/vue";

const { addFile } = useCourier({
  url: "/api/uploads",
  fileChunking: {
    route: "/api/uploads/chunks",
    threshold: 10 * 1024 * 1024,
    chunkSize: 5 * 1024 * 1024,
    maxChunkRetries: 2,
  },
});

Files at or below the threshold use the regular url endpoint. Larger files use fileChunking.route instead.

Configuration ​

PropertyTypeDescription
routestringEndpoint that receives each chunk.
thresholdnumberFile size in bytes at which chunking begins.
chunkSizenumberSize of each chunk in bytes. Defaults to threshold, so set it when threshold is 0.
maxChunkRetriesnumberAdditional attempts for a failed chunk. Defaults to 2.

All sizes are measured in bytes. For example, 10 * 1024 * 1024 represents 10 MiB.

How a chunked upload works ​

For a file with a size of 12 MiB and a chunkSize of 5 MiB, useCourier sends three requests:

  1. Chunk 0: bytes 0 through 5 MiB
  2. Chunk 1: bytes 5 MiB through 10 MiB
  3. Chunk 2: the remaining 2 MiB

The requests are sent one at a time. Each request uses multipart/form-data and includes:

FieldDescription
fileThe current chunk as a file part.
uploadIdA unique ID shared by every chunk in this upload.
chunkIndexThe zero-based index of the current chunk.
totalChunksThe total number of chunks for the file.

The final chunk response becomes the data value returned by addFile or retryUpload, so it must be valid JSON. Responses to earlier chunks are never read: any 2xx status, including an empty 204, counts as the chunk being received.

Progress and retries ​

Progress is reported as the total number of bytes sent across all chunks, not just the current chunk. This means the uploadProgress value continues smoothly from one chunk to the next.

If a chunk fails, useCourier retries that chunk up to maxChunkRetries additional times before marking the upload as failed. Cancellation is not retried. Calling removeFile aborts the active request and removes the file from the tracked list.

Calling retryUpload after a chunked upload fails resumes from the chunk that failed — the same uploadId, picking up at that chunkIndex — rather than starting over. If chunkSize or route changed since the failure, it starts over under a new uploadId instead, since chunks of a different size would corrupt the file. See Upload Lifecycle for the full explanation, including the other case (a page reload mid-upload) that still starts over from scratch.

Server responsibilities ​

The chunk endpoint must:

  1. Read the file, uploadId, chunkIndex, and totalChunks fields.
  2. Store each chunk under its uploadId and chunkIndex.
  3. Detect when all chunks for an upload have arrived.
  4. Reassemble the chunks in index order.
  5. Return the completed upload response from the final request.

The client does not reassemble the file. Your server must also clean up incomplete or expired uploads so abandoned chunks do not accumulate indefinitely.

Choosing chunk sizes ​

A larger chunk size means fewer requests and less request overhead, but each retry sends more data. A smaller chunk size can make retries cheaper and may work better with request-size limits, but it creates more requests.

Choose a threshold and chunkSize that fit your server's request limits and storage strategy.