Next.js Discord

Discord Forum

Parallel server actions request

Answered
Giant Angora posted this in #help-forum
Open in Discord
Giant AngoraOP
Hi everyone! I’m working on a file upload feature in my Next.js 15 app, and I’ve noticed that when I use server actions for file uploads, the requests seem to go out sequentially, causing delays. But when I switch to using fetch with an API route, the requests go out in parallel as expected.

Could anyone explain why server actions might be serializing these requests, or if there’s a workaround to make them handle parallel uploads effectively? I’d appreciate any guidance or insights!"

Additional Info:

Setup: Using Next.js 15 with server actions for file uploads.
Goal: Send multiple file uploads in parallel.
Working Solution: Using fetch with API routes works, but I’m curious about server actions.
Answered by B33fb0n3
server actions will run only run one after another. If you really need parallel uploads make sure you using a route handler
View full answer

12 Replies

Brown bear
A minimal reproducable example would be very helpful for this. Even with dummy delays on the "work" part (something like await new Promise(r => setTimeout(r, 2000));) as long is it shows the issue.
Answer
@Brown bear A minimal reproducable example would be very helpful for this. Even with dummy delays on the "work" part (something like `await new Promise(r => setTimeout(r, 2000));`) as long is it shows the issue.
Giant AngoraOP
const handleFiles = async (
  event: React.ChangeEvent<HTMLInputElement>,
) => {
  const files = event.target.files;

  if (!files) return;

  const filesArr: FileObject[] = Array.from(files).map((file) => ({
    id: createId(),
    file,
    haveRequestSent: false,
    status:
      file.size <= 50 * 1024 * 1024 ? 'uploading' : 'sizeExceed',
  }));

  setFiles((prev) => [...filesArr, ...prev]);
  setUploadDialogOpen(true);
  setIsMinimized(false);

  filesArr
    .filter(
      (ele) => !ele.haveRequestSent && ele.status === 'uploading',
    )
    .map(async (ele) => {
      setFiles((prev) =>
        prev.map((item) =>
          item.id === ele.id
            ? { ...item, haveRequestSent: true }
            : item,
        ),
      );

      const formData = new FormData();

      formData.set('file', ele.file);

      const res = await fetch('/api/file-upload', {
        method: 'POST',
        body: formData,
      });

      const { success, newFile } = await res.json();

      setFiles((prev) =>
        prev.map((item) =>
          item.id === ele.id
            ? {
                ...item,
                status: success && newFile ? 'uploaded' : 'failed',
              }
            : item,
        ),
      );
    });
};
@Brown bear do you need example with server action...?
if you want parallel execution, use a route handler.
Server Actions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing Server Actions typically process one action at a time and do not have a way to cache the return value.
Giant AngoraOP
thx for your precious time ❤️ @Brown bear @B33fb0n3
Brown bear
Be sure to mark the answer so people see the question is closed!
Original message was deleted
Brown bear
like so
happy to help 🙂