Uploading Files in Next.js
To upload files in Next.js, you need to set up an API route that can handle incoming requests and read files from them. You also need a client side component that has an input that allows the user to upload a file. Now let’s get those things set up.
Uploading a File to a Server
Start by setting up a basic API route that can handle incoming requests.
Create a file app/api/file/route.ts
if you are using App Router in your project. For Page Router, you will have to do some adjustments to the code and create a file in pages/api/file.ts
instead.
If you are sending a single file and your server can handle it, you can send it as raw data. If you want to include other data in your request or have multiple files, skip ahead and see how to use multipart/form-data
instead.
'use client'
import React from 'react';
export default function FileUpload() {
async function handleFileUpload(event: React.ChangeEvent<HTMLInputElement>) {
if (!event.target.files || event.target.files.length === 0) {
return; // User canceled file selection
}
const file = event.target.files[0];
await fetch('/api/file', {
method: 'POST',
body: file,
headers: {
'Content-Type': file.type,
},
});
}
return (
<input
type="file"
onChange={handleFileUpload}
/>
);
}
You can set the Content-Type
header to communicate to the server what kind of file the data represents.
From there you can interpret the received file data from the request and do what you need to do with it. In Next.js you can convert the received data from request into a Blob
by calling blob
method on request
.
export async function POST(request: Request): Promise<Response> {
const blob = await request.blob();
console.log(blob);
return new Response();
}
To upload multiple files you can use multipart/form-data
instead.
First, set the input
to allow multiple file selection.
<input
type="file"
onChange={handleFileUpload}
multiple={true}
/>
Next, create a FormData
object and append
each file individually to it. To easily loop over the files
, you can convert files from a FileList
to an array using Array.from
. This approach also allows you to add other data to the request that you send to the server — otherData
in this case.
async function handleFileUpload(event: React.ChangeEvent<HTMLInputElement>) {
if (!event.target.files || event.target.files.length === 0) {
return; // User canceled file selection
}
const files = event.target.files;
const formData = new FormData();
for (const file of Array.from(files)) {
formData.append('files', file);
}
formData.append('otherData', 'some data');
await fetch('/api/file', {
method: 'POST',
body: formData,
});
}
On the server, you can access all of the files by reading the form data from request
with the formData
method and then calling getAll
method. Pass it the same key name you used on the client when appending files to form data.
export async function POST(request: Request): Promise<Response> {
const formData = await request.formData();
console.log(formData.getAll('files'));
return new Response();
}