Skip to content
D
Documentation

Cancellation and progress

how-to
2 min readUpdated

Cancel requests and report progress

Use ky with an AbortSignal to cancel a request, and use the progress callbacks in Options to update upload or download status when the runtime supports streaming. The callback receives a Progress object and the current byte chunk.

When to use this

Use cancellation when a view closes, a newer request supersedes an older one, or the user explicitly stops a transfer. Use progress callbacks when a streamed body is large enough that the user needs feedback during the transfer.

Cancel a request

Create an AbortController, pass its signal, and call abort() from the event that stops the work. The request rejects with an abort error, so handle that case separately from other failures.

ts
import ky from 'ky';

const run = async (): Promise<void> => {
	const controller = new AbortController();
	const {signal} = controller;
	const requestUrl = 'https://example.com/long-running-report';

 	const request = ky.get(requestUrl, {signal}).text();

 	setTimeout(() => {
		controller.abort();
	}, 5000);

	try {
		const report = await request;
		console.log(report);
	} catch (error) {
		if (error instanceof Error && error.name === 'AbortError') {
			console.log('Request cancelled');
		} else {
			throw error;
		}
	}
};

void run();

The request stops when the controller is aborted; the catch block identifies that cancellation by the error name and rethrows unrelated errors.

Report download progress

Pass onDownloadProgress to the request. Ky calls it as response chunks arrive. percent ranges from 0 to 1, transferredBytes counts received bytes, and totalBytes is an estimate that can be 0 when the size is unavailable.

ts
import ky from 'ky';

const run = async (): Promise<void> => {
	const downloadUrl = 'https://example.com/files/archive.zip';

 	const response = await ky.get(downloadUrl, {
		onDownloadProgress: (progress, chunk) => {
			const percentage = Math.round(progress.percent * 100);
			console.log(`${percentage}%`, progress.transferredBytes, progress.totalBytes, chunk.byteLength);
		},
	});

 	const archive = await response.blob();
 	console.log(archive.size);
};

void run();

The callback reports each received chunk, including an empty final chunk when the response body is empty. The final progress report has percent equal to 1; totalBytes can still reflect an estimate rather than a server-provided exact size.

Report upload progress

Pass the upload body and onUploadProgress to a method shortcut such as ky.post(). A Blob gives Ky a body size it can use for the progress estimate.

ts
import ky from 'ky';

const run = async (): Promise<void> => {
	const upload = new Blob(['row,quantity\nwidget,12\n'], {type: 'text/csv'});

 	await ky.post('https://example.com/uploads/inventory.csv', {
		body: upload,
		onUploadProgress: (progress, chunk) => {
			const percentage = Math.round(progress.percent * 100);
			console.log(`${percentage}%`, progress.transferredBytes, progress.totalBytes, chunk.byteLength);
		},
	});
};

void run();

The callback reports bytes as Ky sends the request body and finishes with a progress value of 1. The upload callback is silently ignored when request stream support is unavailable, when keepalive is true, or when the effective request mode is 'no-cors'; do not use it as the only indication that an upload started or finished in those environments.

Options

OptionTypeDefaultWhat it does
signalAbortSignal | null | undefined—Supplies the signal that aborts the request.
onDownloadProgress(progress, chunk) => void—Receives download progress and each received Uint8Array chunk.
onUploadProgress(progress, chunk) => void—Receives upload progress and each sent Uint8Array chunk.
keepaliveboolean—When true, prevents Ky from using a streamed request body for upload progress.

Pitfalls

  • Cancellation is cooperative: keep the controller and call abort() from the owner of the request, such as a cancel button or a component cleanup handler.
  • totalBytes can be 0 when the transfer size cannot be determined. Display transferred bytes or an indeterminate indicator instead of treating 0 as a zero-byte transfer.
  • Upload progress depends on request-stream support and HTTP/2 for HTTPS connections in Chromium-based browsers. Check the runtime requirements before making a determinate upload progress bar part of the interface.

For reusable URL or retry defaults, see shared clients and URL defaults. For Ky's failure categories, see Ky's error model.

Was this page helpful?

Cancellation and progress — ky · GPT-5.6 Luna