Proxy · File upload

GraphQL File Upload for Federated APIs

Clients send files alongside their GraphQL mutation. The router routes them to the right subgraph automatically.

One GraphQL endpoint. One auth layer. No encoding bloat.

Multipart request flow

Clientmultipart/form-dataoperations · map · filesCosmo Routerparse · validate · routeSubgraphUpload scalar

Available onFreeProEnterprise

The problem

Uploads should not live outside your graph

Federated teams still need files: avatars, attachments, imports. The wrong defaults split your API and punish bandwidth.

A separate REST endpoint fragments the API

When uploads bypass GraphQL, teams often reimplement authentication, rate limiting, and logging on a second path. Errors and traces follow different shapes than the rest of the API, and clients carry an extra integration for the same product.

Base64 over JSON wastes bandwidth

Putting binary data inside JSON usually means base64, which grows the payload by roughly a third compared to the raw file. Parsing that JSON costs more CPU on both sides, and the extra bytes add up across large files and repeated attempts.

Custom upload schemes don't travel

If each team invents its own envelope, every client library, SDK, and piece of tooling has to learn each one. Standard clients (Apollo, Relay, urql) already speak the multipart spec.

Our solution

Accept file uploads through your GraphQL API with no second endpoint

Cosmo Router implements the GraphQL multipart request specification. Clients send a multipart/form-data request with three parts: operations, map, and file parts. Declare an Upload scalar in your schema and you can accept files from any spec-compliant client.

The three parts

  • operations: the GraphQL query with file variables set to null
  • map: associates file fields to variable paths
  • file parts: the actual bytes

At request time

  1. Instead of splitting uploads onto a separate REST service, callers use the same federated GraphQL URL they already use for reads and mutations. The router accepts a multipart body, interprets it according to the spec, and continues the request as normal GraphQL work.

  2. The router parses the payload, validates the mapping, and attaches each file to the correct variable before federation routes the mutation.

  3. Declare an `Upload` scalar in your schema and implement it in the resolver layer: any spec-compliant client can send files through the same GraphQL endpoint as everything else.

  4. File size and file count limits are configured on the router in `config.yaml`; malformed multipart requests are rejected at the router.

One endpoint. Standard tooling. Binary on the wire.

File upload

Before & After

Before CosmoWith Cosmo
Separate REST endpoint for uploadsOne GraphQL endpoint for everything
Base64 encoding with 33% overheadBinary multipart transfer
Custom routing logic for uploadsAutomatic federation routing
Bespoke upload envelopes per clientStandard spec any major client speaks

Router behavior

Technical behavior

  • The router parses multipart payloads per spec and rejects malformed ones.
  • File size and file count limits are configured on the router in config.yaml.
  • Files are forwarded to the subgraph that resolves the mutation.
  • Works with Apollo Client, Relay, urql, and other spec-compliant clients out of the box.

Requirements

  • Declare scalar Upload in the subgraph schema and implement it in resolvers.
  • Use a multipart-capable GraphQL client.

How multipart upload works

01
De facto standard across GraphQL clients.

One POST to your GraphQL endpoint

Clients keep the same gateway URL; the body is multipart instead of JSON-only, using the shape common GraphQL clients already support.

02
Malformed uploads rejected early.

Router parses the payload

Reads the three parts, validates the mapping, attaches each file to the correct variable.

03
Automatic federation routing.

Router forwards to the subgraph

Upload travels to the subgraph that owns the mutation.

04
Binary: no base64 tax.

Subgraph stores or processes the file

Resolver writes to S3, disk, or another service and returns the mutation result.

Schema examples

Declare Upload once

Avatar, multi-file tickets, or bulk import: same scalar pattern.

Example schema

GraphQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Limits in config

config.yaml

Cap upload size and file count at the router. See the docs for all options.

1
2
3
4

Upload through GraphQL today

Multipart spec, one router endpoint, configurable limits.

FAQ

GraphQL file upload

More detail in the file upload documentation.