Minimal example of file upload using Next.js app router

Software engineer. Interested in small and efficient tech product teams and ambitious projects that move things forward.
Search for a command to run...

Software engineer. Interested in small and efficient tech product teams and ambitious projects that move things forward.
No comments yet. Be the first to comment.
Hello to anyone that might reach this website! Just want to let you know that I've changed the place where I publish and build new things. You can find things I'm up to on apisurf.dev. Cheers!
There are two good articles that touch on some of the concerns and annoyances I also share, but I'll try to cover some of my views about it. I had a chance to use Next.js 13 for a few weeks and noticed that some things make my job a lot simpler, whil...
new Date('YYYY-MM-DD') might not do what you think it does

Recently I stumbled upon an interesting test case where I needed to cover many possibilities and make sure everything continues to work as intended in the future. I had 7 boolean flags that needed to be used to toggle an app functionality. It's a bit...

Some old methods of accessing uploaded file contents inside a Next.js route handler don't work anymore or at least not in a way many tutorials explain it. E.g. many outdated online examples use page router which has route handlers that receive different types of arguments.
Following is a minimal proof of concept that you can extend upon to provide better UX and save or process the file, add error handling etc. The example is intentionally bare bones and not using any libraries to get down to the gist of things. It sets up a minimal example that accepts and reads a file.
<input type="file" />
<script>
document
.querySelector('input[type="file"]')
.addEventListener('change', function(event) {
const file = event.target.files[0];
const formData = new FormData();
formData.append('file', file);
fetch(
'/api/upload-route',
{ method: 'POST', body: formData }
);
})
</script>
This creates a raw HTML input field with "onchange" event handler attached to it. When a file is selected, it automatically appends its content to FormData object as a file field and makes a POST request using it for the body of the request. By using FormData, we produce a multipart/form-data encoded POST request. Simply put, we are sending a specific type of message to the server that can have multiple parts(i.e. text fields, files, etc.) and they are separated by a specified boundary.
const readFile = (req: Request): Promise<string> =>
new Promise(async (resolve, reject) => {
const data = await req.formData();
const file = data.get('file') as File | null;
if (!file) {
return reject('No file sent!');
}
const buffer = Buffer.from(await file.arrayBuffer());
const content = buffer.toString('utf8');
resolve(content);
});
export async function POST(req: Request) {
const content = await readFile(req);
const responseBody = JSON.stringify({ content })
return new Response(responseBody);
}
On the Next.js side, we reverse the process. We call req.formData() to get the FormData sent from the client side. Read a specific field named file by using data.get('file') and then load the binary file content into a new Buffer and decode the content as a utf8 string.POST handler function just uses decoded file contents to loop them back to the client inside a response to this API call.
This example assumes you have a textual file being uploaded and you need to access its contents inside an API route handler function. In case the file is binary, you'd probably want to skip the "read" part and just save or transition the contents to some other place.
Thank you for reading and Godspeed!