How to Implement Download Files in NextJS using an API Route
![Jasser Mark Arioste Jasser Mark Arioste](https://api.reacthustle.com/image?url=https://static.reacthustle.com/uploads/f4f5cbec4f331597effb22a00.jpeg?w=40&q=100)
Jasser Mark Arioste
Hello, hustlers! In this tutorial, you'll learn how to send files from an API route in NextJS 13 /app
ย and /api
folders.ย
Introduction #
It's common practice to store files to a third-party service like AWS S3, Digital Ocean Spaces, or Azure blob storage but we don't want the client to access the URL from those services directly. It's a best practice to create a proxy like an API route in your backend server.ย
The diagram below illustrates the process described above:
Tutorial Objectives #
In this tutorial, you'll learn the following:
- Create an API route to send files using theย
/app
router of NextJS 13. - Create an API route to send files using the
/pages
directory of NextJS 12.
This way, you'll have two options depending on what version of NextJS you are using. The implementation is different in both options but I prefer using the /app
directory since it's more straightforward and I find the code more readable.
Option 1: Using the /app
router
#
First, let's create the route by creating the file /app/download/[filename]/route.ts
. Your directory should look like this:
๐ app ๐ download ๐ [filename] route.ts
123
The route.ts file is a special file for route handlers in NextJS that indicates that a path is an API route. Here we can access the API through the following route for example: /api/download/dummy.pdf
.
Here's how to implement the actual download:
type GetParams = { params: { filename: string; }; }; // export an async GET function. This is a convention in NextJS export async function GET(req: Request, { params }: GetParams) { // filename for the file that the user is trying to download const filename = params.filename; // external file URL const DUMMY_URL = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"; // use fetch to get a response const response = await fetch(DUMMY_URL); // return a new response but use 'content-disposition' to suggest saving the file to the user's computer return new Response(response.body, { headers: { ...response.headers, // copy the previous headers "content-disposition": `attachment; filename="${filename}"`, }, }); }
1234567891011121314151617181920212223242526
Now, once we go to /api/download/dummy.pdf
, you should see the file being downloaded by the browser:
Option 2: Using the /pages/api
directory
#
Next, let's implement file download using the /pages
directory. If you're using Next 13 but haven't adapted to the new /app
directory, then you can use this method. Otherwise, I recommend the previous method since it's much easier to implement.
I find that using axios
package is easier in this scenario so let's install it first:
yarn add axios
1
First, create the file /pages/api/_download/[filename].ts
. I used _download to avoid route conflict with the /app
folder.
import axios from "axios"; import { NextApiRequest, NextApiResponse } from "next"; import { Readable } from "stream"; async function handler(req: NextApiRequest, res: NextApiResponse) { // get the filename for the file that the user is trying to download const filename = req.query.filename; // external file URL const DUMMY_URL = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"; // use axios to get a Readable stream response const { data } = await axios.get<Readable>(DUMMY_URL, { responseType: "stream", }); res.setHeader("content-disposition", `attachment; filename="${filename}"`); // pipe the data to the res object data.pipe(res); } export default handler;
123456789101112131415161718192021222324
Here, the code is pretty similar to the first option, but instead of returning a Response
object, we use .pipe
to copy all the data from the stream to the res
object.
Full Code #
You can access the full code at my GitHub repo: jmarioste/next-js-download-file
Conclusion #
You learned how to create download APIs using NextJS /app
router and /pages/api
routes.
If you like this tutorial, please leave a like or share this article. For future tutorials like this, please subscribe to our newsletter or follow me on GitHub.
Resources #
Credits:ย Image by Vero_Fasching from Pixabay