How to Upload Multiple Files in GraphQL: Syntax and Example
To upload multiple files in
GraphQL, use the graphql-upload specification which supports multipart requests. Define your mutation to accept an array of Upload scalar types, then send files as an array in the request. This allows you to handle multiple file uploads in a single GraphQL mutation.Syntax
Use a mutation that accepts an array of Upload types. The Upload scalar handles file streams. The client sends files as multipart form data with a map linking files to variables.
- mutation: Defines the operation to upload files.
files: [Upload!]!: An array of non-null files.graphql-upload: Middleware or library to process multipart requests.
graphql
mutation UploadMultipleFiles($files: [Upload!]!) {
uploadFiles(files: $files) {
filename
mimetype
encoding
}
}Example
This example shows a Node.js GraphQL server using graphql-upload to accept multiple files and return their details. The client sends files as an array in the files variable.
javascript
const { ApolloServer, gql } = require('apollo-server-express'); const { GraphQLUpload, graphqlUploadExpress } = require('graphql-upload'); const fs = require('fs'); const express = require('express'); const typeDefs = gql` scalar Upload type File { filename: String! mimetype: String! encoding: String! } type Mutation { uploadFiles(files: [Upload!]!): [File!]! } `; const resolvers = { Upload: GraphQLUpload, Mutation: { uploadFiles: async (_, { files }) => { const results = []; for await (const file of files) { const { filename, mimetype, encoding, createReadStream } = await file; // Example: save file to disk (optional) const stream = createReadStream(); const path = `./uploads/${filename}`; await new Promise((resolve, reject) => { const writeStream = fs.createWriteStream(path); stream.pipe(writeStream); writeStream.on('finish', resolve); writeStream.on('error', reject); }); results.push({ filename, mimetype, encoding }); } return results; }, }, }; const app = express(); app.use(graphqlUploadExpress()); const server = new ApolloServer({ typeDefs, resolvers, uploads: false, }); server.start().then(() => { server.applyMiddleware({ app }); app.listen({ port: 4000 }, () => { console.log(`Server ready at http://localhost:4000${server.graphqlPath}`); }); });
Output
Server ready at http://localhost:4000/graphql
Common Pitfalls
- Not using
graphql-uploadmiddleware causes file streams to be unavailable. - Defining the mutation to accept a single
Uploadinstead of an array[Upload!]!limits to one file. - Forgetting to handle asynchronous file streams properly can cause errors or incomplete uploads.
- Client must send files using multipart/form-data with correct map and operations fields; otherwise, uploads fail.
graphql
/* Wrong: single file upload only */ mutation UploadFile($file: Upload!) { uploadFile(file: $file) { filename } } /* Right: multiple files upload */ mutation UploadMultipleFiles($files: [Upload!]!) { uploadFiles(files: $files) { filename } }
Quick Reference
| Step | Description |
|---|---|
| Define mutation | Use an array of Upload scalar: files: [Upload!]! |
| Use graphql-upload | Add middleware to parse multipart requests |
| Client request | Send files as multipart/form-data with map and operations |
| Handle streams | Process each file stream asynchronously in resolver |
| Return info | Return file metadata or URLs after upload |
Key Takeaways
Use the Upload scalar array [Upload!]! in your mutation to accept multiple files.
Add graphql-upload middleware to your server to handle multipart file uploads.
Send files from the client as multipart/form-data with proper mapping to variables.
Process file streams asynchronously in your resolver to save or handle files.
Avoid defining mutations for single files if you need to upload multiple files.