Open In App

How to Implement File Download in NextJS using an API Route ?

Last Updated : 13 May, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

In web development, facilitating file downloads is a common requirement, whether it's providing users with documents, images, or other media files. NextJS, with its versatile API routes and server-side capabilities, offers an elegant solution for implementing file downloads. In this article, we'll explore how to leverage NextJS API routes to enable seamless file downloads in your applications.

Why Use API Routes for File Download?

NextJS API routes provide a server-side environment where you can execute custom logic, making them an ideal choice for handling file downloads. By using an API route, you can:

  • Access server-side resources securely.
  • Dynamically generate files on the fly.
  • Implement authentication and authorization logic if necessary.
  • Ensure consistent behavior across different client environments.

Steps to Setup a NextJS App

Step 1: Create a NextJS application using the following command.

npx create-next-app@latest <foldername>

Step 2: It will ask you some questions, so choose the following.

√ Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... No
√ Would you like to use `src/` directory? ... Yes
√ Would you like to use App Router? ... Yes
√ Would you like to customize the default import alias (@/*)? ... No

Step 3: After creating your project folder, move to it using the following command.

cd <foldername>

Steps to Implement File Download in NextJS

Let's walk through a step-by-step process to implement file downloads in NextJS using an API route:

Step 1: Create an API Route

First, create an API route in your NextJS project where you'll handle the file download logic. This route will be responsible for fetching the file from the server and sending it as a response to the client. for instance we will use the images in our project itself like NexJs.svg or favicon.ico to be able to download by the client.

JavaScript
// pages/api/download.js

const fs = require("fs");
const path = require("path");

export default function handler(req, res) {
    const filePath = path.join(process.cwd(),
        "public", "next.svg"); // Path to your file
    // Filename for the downloaded file
    const fileName = "gfgNextJs.svg";

    // Check if the file exists
    if (!fs.existsSync(filePath)) {
        return res.status(404).send("File not found");
    }

    // Define a mapping of file extensions to content types
    const contentTypeMap = {
        svg: "image/svg+xml",
        ico: "image/x-icon",
        png: "image/png",
        jpg: "image/jpeg",
        pdf: "application/pdf",
        // Add more mappings as needed for other file types
    };

    // Get the file extension
    const fileExtension = fileName.split(".").pop().toLowerCase();

    // Determine the content type based on the file extension
    const contentType =
        contentTypeMap[fileExtension] || "application/octet-stream";

    // Set headers to force download
    res.setHeader("Content-Disposition",
        `attachment; filename="${fileName}"`);
    res.setHeader("Content-Type", contentType);

    // Stream the file
    const fileStream = fs.createReadStream(filePath);
    fileStream.pipe(res);
}

Step 2: Call the API Route from Client-Side

Next, you'll need to trigger the file download from your client-side components. You can use a simple HTTP request or a library like Axios to fetch the file from the API route. this results in the download of the required file.

JavaScript
// pages/index.js

import Head from "next/head";
import { useState } from "react";
import axios from "axios";

export default function Home() {
    const [downloadStatus, setDownloadStatus] = useState("");

    const downloadFavicon = async () => {
        try {
            const response = await axios.get("/api/download", {
                responseType: "blob", // Important for binary data
            });

            // Extract filename from content-disposition header
            const contentDisposition = response.headers["content-disposition"];
            const fileNameMatch = contentDisposition.match(/filename="(.+)"/);
            const fileName = fileNameMatch ? fileNameMatch[1] : "downloadedFile";

            // Create a temporary anchor element to trigger the download
            const url = window.URL.createObjectURL(new Blob([response.data]));
            const link = document.createElement("a");
            link.href = url;
            // Setting filename received in response
            link.setAttribute("download", fileName);
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);

            setDownloadStatus("Downloaded");
        } catch (error) {
            console.error("Error downloading file:", error);
            setDownloadStatus("Error downloading");
        }
    };

    return (
        <>
            <Head>
                <title>Create Next App</title>
                <meta name="description"
                    content="Generated by create next app" />
                <meta name="viewport"
                    content="width=device-width, initial-scale=1" />
                <link rel="icon" href="/favicon.ico" />
            </Head>
            <main>
                <div style={{ height: "100vh", backgroundColor: "white" }}>
                    <button style={{ fontSize: "25px" }}
                        onClick={downloadFavicon}>
                        Download gfgNextJS
                    </button>
                    <p>{downloadStatus}</p>
                </div>
            </main>
        </>
    );
}

Start your application using the following command:

npm run dev

Output:

file download in next js using api routes
Download Files in NextJS using an API Route


donw
downloaded svg image

Step 3: Customize the Downloadable files as needed

Adjust the filePath variable to point to the actual location of your file in the public directory. Also, set the appropriate fileName and Content-Type headers.

  • For SVG files, use "image/svg+xml" as the content type.
  • For ICO (icon) files, use "image/x-icon" as the content type.
  • For PDF set Content-Type header to application/pdf

Step 4: Customizing React Home Component

In the React component, customize the user interface to provide a user-friendly way to trigger the PDF download. This may include designing a button or a link with appropriate text and styling. Consider adding informative messages or visual cues to indicate the download status to the user.

Step 5: Testing

Once you've made changes to the component, make sure to test the PDF download. Click the download button to get the PDF file. Check that the file you downloaded is indeed a PDF and has the right content. Also, keep an eye out for any errors or weird things that might happen during the download.

Conclusion

Setting up file downloads in NextJS using an API route is simple. Just follow the steps in this guide, and you'll be able to let users download files from your NextJS app easily. Whether you're serving static files or creating content on the fly, NextJS API routes make it easy to handle file downloads, giving your users a smooth experience.



Next Article

Similar Reads