File Uploads with Next.js
Introduction
Next.js doesn't come with any built-in support for file uploads, but it's surprisingly easy to setup with a helpful library.
Requirements
You'll need need to install the async-busboy NPM package:
npm i async-busboy
asyncBusboy is a simple async wrapper around the main library, busboy.
You can read more about async-busboy here
Before we kick things off...
If you haven't yet stumbled upon my post on Using Middleware with Next.js. I'd recommend giving it a read. I'll be using a custom middleware in this example to handle file uploads.
Step 1: Upload Middleware
We're going to create a Middleware that extends the functionality of our Next.js API routes.
This middleware is designed to look for POST
requests with a file upload content type. When those requirements are met, the req
object is
passed to busboy so it can process the uploaded files and give us back something we can use.
// lib/middleware.js
import asyncBusboy from "async-busboy";
export default Middleware (handler) => async (req, res) => {
// we only care about POST's with a Content-Type of multipart/form-data
if (req.method == "POST" && req.headers['content-type'].includes('multipart/form-data')) {
// busboy will parse the req and extract the uploaded files
const { files } = await asyncBusboy(req);
// extend the req object with the processed files
// we'll be able to access this in our API route later
req.files = files;
}
// pass on the req and res to the API Route
return handler(req, res);
}
Step 2: API Route
This route can be customized as needed, for example sake, it's just showing how the Middleware
wraps the route and req.files
is now available in the route file.
// pages/api/upload.js
export default Middleware(async (req, res) => {
// a handle to the first file uploaded
const fileReadStream = req.files[0]
res.json({ success: true, message: 'Files Uploaded' })
})
Reading the Uploaded Files
Disclaimer: this section assumes you have some background with Node Streams and Buffers.
Busboy returns a NodeJS ReadStream
for each file. (More on ReadSteam)
Depending on the use case, you can commonly approach a file upload in two ways.
Option 1: Write to File System
This option is useful when you want to write the uploaded file to the local file system.
- First convert the
ReadStream
to aBuffer
. - Then use
fs.writeFile("path/to/file.jpg", buffer)
to write the file to the file system.
Option 2: Read Contents in Memory
Maybe you just want to read and process the uploaded file, but not actually write it to the file system.
- First convert the
ReadStream
to aBuffer
. - Then convert the
Buffer
to a string.