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.

  1. First convert the ReadStream to a Buffer.
  2. 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.

  1. First convert the ReadStream to a Buffer.
  2. Then convert the Buffer to a string.