GraphQL in Production · Advanced GraphQL

Files and Binary Data in GraphQL

Why multipart uploads are discouraged and what to do instead.

The GraphQL multipart request spec exists, but uploading files through GraphQL servers is discouraged: it complicates CSRF protection, buffering and gateways. The common pattern is: a mutation returns a pre-signed upload URL, the client uploads directly to object storage, then a second mutation attaches the uploaded file. Return files as URLs (signed, short-lived for private content), never base64 blobs in responses.

Upload options

Criterion Multipart via GraphQL Pre-signed URL flow Base64 in JSON
Server load High None Very high (+33% size)
CSRF exposure Needs extra care None None
Large files Poor Excellent Unusable
Gateway support Inconsistent Universal Universal
type Mutation {
  createUpload(input: CreateUploadInput!): CreateUploadPayload!   # returns signed URL + uploadId
  attachAvatar(input: AttachAvatarInput!): AttachAvatarPayload!   # uploadId → user.avatar
}
type CreateUploadPayload { uploadId: ID!  url: String!  fields: JSON  expiresAt: DateTime! }

Common pitfalls

  • Base64 file payloads.
  • Multipart endpoints without CSRF protection.
  • Long-lived public file URLs.

Key points

  • Signed URL + attach mutation
  • Files as URLs in responses
  • Avoid base64

Further reading: Apollo: File uploads guidance

Practice questions

Why is multipart upload support in GraphQL servers a CSRF concern?

Answer

Multipart/form-data is a 'simple' content type browsers can send cross-site without preflight, so cookie-authenticated endpoints accepting it need explicit CSRF protection.

How should a GraphQL API return a private file?

Answer

As a short-lived signed URL field, generated after authorization, rather than embedding file bytes.

Open in the app to mark lessons complete, take notes and track your progress.