• v3 (beta)
  • Features
  • File Uploads

File Uploads

GraphQL Yoga supports GraphQL Multipart Request Specification which basically allows you to upload files via HTTP and consume the binary data inside GraphQL Resolvers.

In GraphQL Yoga, you consume uploaded files or blobs as WHATWG standard File or Blob objects you might be familiar from the browser's API.

Check out MDN documentation to learn more about File objects

You can use any kind of client supports GraphQL Upload specification. Check out here to find GraphQL Client solutions

Example

You only need to add a scalar type definition for file uploads in your schema. The name of the scalar doesn't matter. Let's use File in this example.

file-upload-example.ts

import { createYoga } from 'graphql-yoga'
 
// Provide your schema
const yoga = createYoga({
  schema: createSchema({
    typeDefs: /* GraphQL */ `
      scalar File
 
      type Query {
        greetings: String!
      }
      type Mutation {
        readTextFile(file: File!): String!
      }
    `,
    resolvers: {
      Query: {
        greetings: () => 'Hello World!'
      },
      Mutation: {
        /**
         * TypeScript type `File` is globally available.
         * You don't need to install/import anything else
         * for both `File` GraphQL Scalar and this type
         */
        readTextFile: async (_, { file }: { file: File }) => {
          const textContent = await file.text()
          return textContent
        }
      }
    }
  })
})
// Start the server and explore http://localhost:4000/graphql
const server = createServer(yoga)
server.listen(4000, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})

Test your GraphQL Server with cURL

curl localhost:4000/graphql \
  -F operations='{ "query": "mutation ($file: File!) { readTextFile(file: $file) }", "variables": { "file": null } }' \
  -F map='{ "0": ["variables.file"] }' \
  -F 0=@mytext.txt

With GraphQL Nexus

You need to create a scalar type for file upload in your schema.

nexus-file-upload-example.ts

import {
  makeSchema,
  scalarType,
  mutationField,
  queryField,
  arg,
  nonNull
} from 'nexus'
import { createYoga } from 'graphql-yoga'
 
const FileScalar = scalarType({
  name: 'File',
  asNexusMethod: 'file',
  description: 'The `File` scalar type represents a file upload.',
  sourceType: 'File'
})
 
const greetings = queryField('greetings', {
  type: 'String',
  resolve: () => 'Hello World!'
})
 
const readTextFile = mutationField('readTextFile', {
  type: 'String',
  args: { file: nonNull(arg({ type: 'File' })) },
  resolve: async (parent, { file }, ctx) => {
    const textContent = await file.text()
    return textContent
  }
})
 
const schema = makeSchema({
  types: [FileScalar, greetings, readTextFile]
})
 
const yoga = createYoga({
  schema: schema
})
 
// Start the server and explore http://localhost:4000/graphql
const server = createServer(yoga)
server.listen(4000, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})

Disabling Multipart/File Upload Processing

If you want to disable multipart request processing for some reason, you can pass multipart: false to prevent Yoga from handling multipart requests.

createYoga({ multipart: false })

Configuring Multipart Request Processing (only for Node.js)

In Node.js, you can configure the limits of the multipart request processing such as maximum allowed file size, maximum numbers of files, etc.

Fetch API's Request.formData method doesn't have any options to configure the limits of Multipart request processing. Instead we can configure our Fetch API ponyfill to manage that.

import { createFetch } from '@whatwg-node/fetch'
import { createYoga } from 'graphql-yoga'
 
createYoga({
  fetchAPI: createFetch({
    // We prefer `node-fetch` over `undici` and current unstable Node's implementation
    useNodeFetch: true,
    formDataLimits: {
      // Maximum allowed file size (in bytes)
      fileSize: 1000000,
      // Maximum allowed number of files
      files: 10,
      // Maximum allowed size of content (operations, variables etc...)
      fieldSize: 1000000,
      // Maximum allowed header size for form data
      headerSize: 1000000
    }
  })
})
Last updated on October 2, 2022