# apollo-upload-client

> A terminating Apollo Link for Apollo Client that fetches a GraphQL multipart request if the GraphQL variables contain files (by default FileList, File, or Blob instances), or else fetches a regular GraphQL POST or GET request (depending on the config and

Latest version **20.0.0** (published 2026-07-29) · MIT license · 0 weekly downloads

## Install

```sh
npm install apollo-upload-client
pnpm add apollo-upload-client
yarn add apollo-upload-client
bun add apollo-upload-client
```

## Health

**Score 53/100 (C)** — status: active.

Positive: has types package; esm support; no vulnerabilities; recently updated; high quality score.

Warnings: low downloads.

Negative: declining downloads.

## Facts

| | |
|---|---|
| Version | 20.0.0 |
| Published | 2026-07-29 |
| First published | 2017-02-24 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | separate (@types/apollo-upload-client) |
| Module format | ESM + CommonJS |
| Node | ^22.13.0 \|\| ^24.0.0 \|\| >=26.0.0 |
| Dependencies | 1 |
| Unpacked size | 21.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1542 |
| Author | Jayden Seric |
| Maintainers | jaydenseric |
| Keywords | graphql, multipart, request, file, upload, apollo, client, link, react, esm, mjs |

## Links

- npm: https://www.npmjs.com/package/apollo-upload-client
- Repository: https://github.com/jaydenseric/apollo-upload-client
- Homepage: https://github.com/jaydenseric/apollo-upload-client#readme
- Issues: https://github.com/jaydenseric/apollo-upload-client/issues
- Funding: https://github.com/sponsors/jaydenseric
- npm.io page: https://npm.io/package/apollo-upload-client

## Dependencies (1)

- [extract-files](https://npm.io/package/extract-files.md) ^14.0.0

## Alternatives

- [apollo-link-http-common](https://npm.io/package/apollo-link-http-common.md) — 879.0K weekly downloads
- [react-relay](https://npm.io/package/react-relay.md) — 336.8K weekly downloads
- [relay-test-utils](https://npm.io/package/relay-test-utils.md) — 181.6K weekly downloads
- [@vendure/core](https://npm.io/package/@vendure/core.md) — 14.8K weekly downloads
- [@pnpm/deps.graph-sequencer](https://npm.io/package/@pnpm/deps.graph-sequencer.md) — 13.4K weekly downloads

## Recent versions

- 20.0.0 (latest) — 2026-07-29
- 19.0.0 — 2025-08-29
- 18.0.1 — 2023-10-24
- 18.0.0 — 2023-10-23
- 17.0.0 — 2021-12-07
- 16.0.0 — 2021-06-11
- 15.0.0 — 2021-05-13
- 14.1.3 — 2020-11-08
- 14.1.2 — 2020-09-12
- 14.1.1 — 2020-07-28
- 14.1.0 — 2020-07-22
- 14.0.1 — 2020-07-20
- 14.0.0 — 2020-07-20
- 13.0.0 — 2020-03-30
- 12.1.0 — 2019-12-03
- … 48 more at https://npm.io/package/apollo-upload-client/versions

## README

![Apollo upload logo](https://cdn.jsdelivr.net/gh/jaydenseric/apollo-upload-client@1.0.0/apollo-upload-logo.svg)

# apollo-upload-client

A [terminating Apollo Link](https://www.apollographql.com/docs/react/api/link/introduction#the-terminating-link) for [Apollo Client](https://www.apollographql.com/docs/react) that fetches a [GraphQL multipart request](https://github.com/jaydenseric/graphql-multipart-request-spec) if the GraphQL variables contain files (by default [`FileList`](https://developer.mozilla.org/en-US/docs/Web/API/FileList), [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File), or [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) instances), or else fetches a regular [GraphQL POST or GET request](https://www.apollographql.com/docs/apollo-server/workflow/requests) (depending on the config and GraphQL operation).

- [Installation](#installation)
- [Examples](#examples)
- [Requirements](#requirements)
- [Exports](#exports)

## Installation

To install with [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), run:

```sh
npm install apollo-upload-client
```

Polyfill any required globals (see [_**Requirements**_](#requirements)) that are missing in your server and client environments.

[Apollo Client](https://www.apollographql.com/docs/react) can only have 1 [terminating Apollo Link](https://www.apollographql.com/docs/react/api/link/introduction#the-terminating-link) that sends the GraphQL requests; if one such as [`HttpLink`](https://www.apollographql.com/docs/react/api/link/apollo-link-http) is already setup, remove it.

Construct [`ApolloClient`](https://www.apollographql.com/docs/react/api/core/ApolloClient) with a [terminating Apollo Link](https://www.apollographql.com/docs/react/api/link/introduction#the-terminating-link) using the class [`UploadHttpLink`](./UploadHttpLink.mjs). For client awareness features, compose the Apollo Link [`ClientAwarenessLink`](https://www.apollographql.com/docs/react/api/link/apollo-link-client-awareness) before the terminating link.

Also ensure the GraphQL server implements the [GraphQL multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec) and that uploads are handled correctly in resolvers.

## Examples

Use [`FileList`](https://developer.mozilla.org/en-US/docs/Web/API/FileList), [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File), or [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) instances anywhere within query or mutation variables to send a [GraphQL multipart request](https://github.com/jaydenseric/graphql-multipart-request-spec).

See also the [example API and client](https://github.com/jaydenseric/apollo-upload-examples).

### [`FileList`](https://developer.mozilla.org/en-US/docs/Web/API/FileList)

```tsx
import { gql } from "@apollo/client";
import { useMutation } from "@apollo/client/react";

/** React component for uploading a file list. */
function UploadFileList() {
  const [mutate] = useMutation<
    {
      uploadFiles: {
        success: boolean;
      };
    },
    {
      files: FileList;
    }
  >(mutation);

  return (
    <input
      type="file"
      multiple
      required
      onChange={({ target: { validity, files } }) => {
        if (validity.valid && files?.length)
          mutate({
            variables: {
              files,
            },
          });
      }}
    />
  );
}

const mutation = gql`
  mutation ($files: [Upload!]!) {
    uploadFiles(files: $files) {
      success
    }
  }
`;
```

### [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File)

```tsx
import { gql } from "@apollo/client";
import { useMutation } from "@apollo/client/react";

/** React component for uploading a file. */
function UploadFile() {
  const [mutate] = useMutation<
    {
      uploadFile: {
        success: boolean;
      };
    },
    {
      file: File;
    }
  >(mutation);

  return (
    <input
      type="file"
      required
      onChange={({ target: { validity, files } }) => {
        if (validity.valid && files?.[0])
          mutate({
            variables: {
              file: files[0],
            },
          });
      }}
    />
  );
}

const mutation = gql`
  mutation ($file: Upload!) {
    uploadFile(file: $file) {
      success
    }
  }
`;
```

### [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)

```tsx
import { gql } from "@apollo/client";
import { useMutation } from "@apollo/client/react";

/** React component for uploading a blob. */
function UploadBlob() {
  const [mutate] = useMutation<
    {
      uploadFile: {
        success: boolean;
      };
    },
    {
      file: Blob;
    }
  >(mutation);

  return (
    <button
      type="button"
      onClick={() => {
        mutate({
          variables: {
            file: new Blob(["Content here."], {
              type: "text/plain",
            }),
          },
        });
      }}
    >
      Upload
    </button>
  );
}

const mutation = gql`
  mutation ($file: Upload!) {
    uploadFile(file: $file) {
      success
    }
  }
`;
```

To avoid the upload default file name `blob`, replace the [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) approach with [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File):

```ts
new File(
  [value],
  // Custom file name.
  "text.txt",
  {
    type: "text/plain",
  },
);
```

## Requirements

- [Node.js](https://nodejs.org) versions `^22.13.0 || ^24.0.0 || >=26.0.0`.
- Browsers matching the [Browserslist](https://browsersl.ist) query [`> 0.5%, not OperaMini all, not dead`](https://browsersl.ist/?q=%3E+0.5%25%2C+not+OperaMini+all%2C+not+dead).

Projects must configure [TypeScript](https://www.typescriptlang.org) to use types from the ECMAScript modules that have a `// @ts-check` comment:

- [`compilerOptions.allowJs`](https://www.typescriptlang.org/tsconfig#allowJs) should be `true`.
- [`compilerOptions.maxNodeModuleJsDepth`](https://www.typescriptlang.org/tsconfig#maxNodeModuleJsDepth) should be reasonably large, e.g. `10`.
- [`compilerOptions.module`](https://www.typescriptlang.org/tsconfig#module) should be `"node16"` or `"nodenext"`.

## Exports

The [npm](https://npmjs.com) package [`apollo-upload-client`](https://npm.im/apollo-upload-client) features [optimal JavaScript module design](https://jaydenseric.com/blog/optimal-javascript-module-design). It doesn’t have a main index module, so use deep imports from the ECMAScript modules that are exported via the [`package.json`](./package.json) field [`exports`](https://nodejs.org/api/packages.html#exports):

- [`formDataAppendFile.mjs`](./formDataAppendFile.mjs)
- [`isExtractableFile.mjs`](./isExtractableFile.mjs)
- [`UploadHttpLink.mjs`](./UploadHttpLink.mjs)

---
_Source: https://npm.io/package/apollo-upload-client · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
