Search code examples
next.jsmultipartform-dataserverless

Server Actions and files


I just want to know is it possible to upload files using server actions to the nextjs project's some folder maybe public folder like storing images, docs, sheets and pdf stuff.

In nodejs we have multer and formidable but I am stuck with server actions because it doesn't use

    'Content-Type': 'multipart/form-data

I need to store applicants like name, email, phone and resume. I want to know is it possible with server actions.

"use server";
import prisma from "@/utils/prisma";
import fs from "fs";
import FormData from "form-data";
import path from "path";
import { v4 as uuid } from "uuid";

const uploadApplicant = async (
  name: string,
  email: string,
  tel: string,
  file: File | null
) => {
  const fileName = uuid();
  const formData = new FormData();

  formData.append("file", file);
  console.log("Form data: ", formData);
  const binaryData = formData.getBuffer();

  console.log("Binary: ");
  console.log(binaryData);

  const filePath = path.join(
    __dirname,
    "../../../../",
    "public",
    "uploads",
    `${fileName}.pdf`
  );

  fs.writeFileSync(filePath, binaryData, "binary");

  await prisma.applicant.create({
    data: {
      name,
      tel,
      email,
      fileName,
    },
  });
};

export default uploadApplicant;

Solution

  • You'll have to grab the File object from the binary FormData instance that get passed to the server action. Try this:

    'use server';
    
    import { writeFile } from 'fs/promises';
    import { join } from 'path';
    
    export async function upload(data: FormData) {
      const file: File | null = data.get('file') as unknown as File;
    
      if (!file) throw new Error('No file uploaded');
    
      const bytes = await file.arrayBuffer();
      const buffer = Buffer.from(bytes);
    
      const path = join(process.cwd(), file.name);
      await writeFile(path, buffer);
    
      console.log(`open ${path} to see the uploaded file`);
    
      return { success: true };
    }