Next.js Upload Image to Public Folder

Photo by Skylar Kang from Pexels


This post is a short demo of how to upload an image to subfolder labeled “\uploads” under the “.\public” folder with Next.JS. Using a page with a file field and a Send to Server button to call a local API that uploads the image to the uploads subfolder under the ./public.

Source Code

GitHub Repo


New Next.js App

Create a new Next.js application

npx create-next-app@latest


Install Formidable for parsing form data.

npm i formidable


Install mv to move the files from temp directory to the public folder.

Vercel recommends that large files should be uploaded to a cloud service like Google Storage Bucket or AWS S3. If moving a file from one location to another using fs it can throw up an error about cross platforms,

npm install mv

Running the Next.JS app

npm run dev

Create the Subfolder

Create a subfolder under ./public labeled uploads. This is where the files will be uploaded.

Upload Image Form

Under pages create a new folder & file “.\pages\uploadform\index.js“. Copy & paste the code below.

import { useState } from "react";

export default function PrivatePage(props) {
  const [image, setImage] = useState(null);
  const [createObjectURL, setCreateObjectURL] = useState(null);

  const uploadToClient = (event) => {
    if ( &&[0]) {
      const i =[0];


  const uploadToServer = async (event) => {        
    const body = new FormData();
    // console.log("file", image)
    body.append("file", image);    
    const response = await fetch("/api/upload", {
      method: "POST",

  return (
        <img src={createObjectURL} />
        <h4>Select Image</h4>
        <input type="file" name="myImage" onChange={uploadToClient} />
          className="btn btn-primary"
          Send to server


Create .\pages\api\upload\index.js and copy & paste the source code below/

import { IncomingForm } from 'formidable'
import { promises as fs } from 'fs'

var mv = require('mv');

export const config = {
    api: {
       bodyParser: false,
export default async (req, res) => {
    const data = await new Promise((resolve, reject) => {
       const form = new IncomingForm()
        form.parse(req, (err, fields, files) => {
            if (err) return reject(err)
            console.log(fields, files)
            var oldPath = files.file.filepath;
            var newPath = `./public/uploads/${files.file.originalFilename}`;
            mv(oldPath, newPath, function(err) {
            res.status(200).json({ fields, files })

Running the Demo

Run the application with npm run dev.

When running the application navigate to “http://localhost:3000/uploadform

Click on Choose File and select an image then click on Send to Server.

Once the file is uploaded it should show up under the “.\public\uploads

Example: Uploaded an image labeled Service.png