File Uploads
GraphQL Yoga supports the GraphQL Multipart Request Specification , allowing you to upload files and consume the binary data inside GraphQL Resolvers via HTTP.
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 the MDN documentation to learn more about File objects
You can use any kind of client supports GraphQL Upload specification. Check out GraphQL Client solutions
Quick start
This guide will show you how to process a file upload in GraphQL Yoga in no time. All you need to do
is adding a File scalar to your schema.
import { createYoga } from 'graphql-yoga'
import { createServer } from 'http'
// Provide your schema
const yoga = createYoga({
schema: createSchema({
typeDefs: /* GraphQL */ `
scalar File
type Query {
greetings: String!
}
type Mutation {
readTextFile(file: File!): String!
saveFile(file: File!): Boolean!
}
`,
resolvers: {
Query: {
greetings: () => 'Hello World!'
},
Mutation: {
readTextFile: async (_, { file }: { file: File }) => {
const textContent = await file.text()
return textContent
}
saveFile: async (_, { file }: { file: File }) => {
try {
const fileArrayBuffer = await file.arrayBuffer()
await fs.promises.writeFile(
path.join(__dirname, file.name),
Buffer.from(fileArrayBuffer),
)
} catch (e) {
return false
}
return true
},
}
}
})
})
// 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')
})After, starting the server, you can use Curl for testing your endpoint.
curl localhost:4000/graphql \
-F operations='{ "query": "mutation ($file: File!) { readTextFile(file: $file) }", "variables": { "file": null } }' \
-F map='{ "0": ["variables.file"] }' \
-F 0=@mytext.txtDisabling 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 })Processing File Uploads as Streams
GraphQL Yoga streams uploaded files directly from the network to your resolver — no buffering occurs until your resolver actually reads the data. This works across all runtimes (Node.js, Cloudflare Workers, Deno, Bun, etc.) using only standard WHATWG APIs.
Each file variable in your resolver is backed by a live ReadableStream that comes directly from
the incoming HTTP connection:
import { createSchema, createYoga } from 'graphql-yoga'
const yoga = createYoga({
schema: createSchema({
typeDefs: /* GraphQL */ `
scalar File
type Mutation {
uploadFile(file: File!): Boolean!
}
`,
resolvers: {
Mutation: {
uploadFile: async (_, { file }: { file: File }) => {
// file.stream() returns a WHATWG ReadableStream – consume it however you like.
// Here we collect all bytes without ever buffering the whole file at once:
const reader = file.stream().getReader()
while (true) {
const { done, value } = await reader.read()
if (done) break
// process chunk (value is Uint8Array)
}
return true
}
}
}
})
})You can also write the file to disk on Node.js using pipeTo with Writable.toWeb:
import { createWriteStream } from 'node:fs'
import { Writable } from 'node:stream'
// Inside your resolver — works in Node.js 18+:
await file.stream().pipeTo(Writable.toWeb(createWriteStream('/tmp/' + file.name)))On Node.js you can also use the traditional pipeline helper:
import { createWriteStream } from 'node:fs'
import { Readable } from 'node:stream'
import { pipeline } from 'node:stream/promises'
// Inside your resolver:
await pipeline(Readable.fromWeb(file.stream()), createWriteStream('/tmp/' + file.name))Notes on streaming mode
- Stream can only be read once. Calling
.stream(),.arrayBuffer(), or.text()more than once on the same file will throw an error. - Backpressure is respected. If the resolver reads slowly, the TCP connection will naturally slow down.
Configuring Multipart Request Limits
You can configure upload limits such as maximum file size and maximum number of files using the
multipart.limits option. These limits are enforced by the built-in streaming parser and work on
every runtime (Node.js, Cloudflare Workers, Deno, Bun, etc.).
import { createYoga } from 'graphql-yoga'
createYoga({
multipart: {
limits: {
// Maximum allowed file size (in bytes)
fileSize: 1_000_000,
// Maximum allowed number of files
files: 10,
// Maximum allowed size of text fields such as `operations` and `map` (in bytes)
fieldSize: 1_000_000
}
}
})Third Party Integrations
Usage with GraphQL Nexus
GraphQL Nexus is a popular library for building GraphQL schemas with TypeScript. It provides a convenient API for defining GraphQL types and resolvers.
import { createServer } from 'http'
import { createYoga } from 'graphql-yoga'
import { arg, makeSchema, mutationField, nonNull, queryField, scalarType } from 'nexus'
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')
})Usage with S3
Amazon S3 is a popular object storage service. You can use GraphQL Yoga to upload files to S3. In this example, we will use the AWS SDK for JavaScript v3 .
Note that S3 is a common protocol and you can use other storage providers than AWS.
import { createServer } from 'http'
import { createYoga } from 'graphql-yoga'
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
const client = new S3Client({})
// Provide your schema
const yoga = createYoga({
schema: createSchema({
typeDefs: /* GraphQL */ `
scalar File
type Mutation {
upload(file: File!): Boolean!
}
`,
resolvers: {
Mutation: {
upload: async (_, { file }: { file: File }) => {
try {
await client.send(
new PutObjectCommand({
Bucket: 'test-bucket',
Key: file.name,
Body: Buffer.from(await file.arrayBuffer())
})
)
return true
} catch (e) {
return false
}
}
}
}
})
})
// 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')
})