JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 1419
  • Score
    100M100P100Q110159F
  • License MIT

Run Next.js server actions in parallel. Like tRPC, but without the boilerplate.

Package Exports

  • next-server-actions-parallel

Readme

Next.js Parallel Server Actions

NPM version License Sponsor the author

Run multiple Next.js server actions in parallel.

The missing ingredient to build tRPC-like workflows, but without the boilerplate.

TL;DR

Install:

pnpm i next-server-actions-parallel

Define your server actions like so:

app/page.actions.ts:

'use server';

import { createParallelAction } from 'next-server-actions-parallel';

export const listUsers = createParallelAction(async () => { // 👈 don't forget the `async` keyword!!
  return prisma.user.findMany(); // 👈 let's assume this takes 3 seconds
});

export const listProducts = createParallelAction(async (categoryId: string) => {
  return prisma.product.findMany({ where: { categoryId } }); // 👈 let's assume this also takes 3 seconds
});

Use them like so:

app/page.tsx:

'use client';

import { runParallelAction } from 'next-server-actions-parallel';
import { listUsers, listProducts } from './page.actions';

export default async function Page() {
  // 👇 this may take slightly more than 3 seconds, but a lot less than 6.
  const [users, products] = await Promise.all([
    runParallelAction(listUsers()),
    runParallelAction(listProducts('82b2ab20-ec1e-4539-85a2-ea6737555250')),
  ]);

  return (
    <div>
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
      <ul>
        {products.map((product) => (
          <li key={product.id}>{product.name}</li>
        ))}
      </ul>
    </div>
  );
}

Why this exists?

Because a lot of people are interested in this feature. See:

How does it perform?

In a nutshell: a lot better than default Next.js server actions, not as fast as REST API routes.
Check it in your specific deployment environment and decide if it makes sense for your project.

Show gratitude

If you find my open-source work useful, please consider sponsing me on GitHub Sponsors.

Background story

When Vercel added support for server actions in Next.js, a lot of developers - myself included - were hyper-excited about it and saw it as a boilerplate-free alternative to tRPC.io to Telefunc.

Many were however disappointed to find that Next.js server actions were executed in series, contrary to what one would expect when triggering them in parallel with Promise.all.
It probably worked like that because they were intended to be used for mutations, because "data should be fetched in server components or using REST API endpoints".
Plus, since server actions are implemented with POST requests, some are reluctant to the idea of using them for fetching data (though POST requests can and usually do return data).

However, there are many reasons why projects like tRPC.io, Telefunc and other *RPCs were built (and have no problem using POST requests to fetch data). If you're building real, data-rich applications you'd definitely want something like tRPC.io for type-safety and the fact that you don't have to build and maintain hundreds of API endpoints just to populate dynamic UI components (autocompletes and selects).

tRPC.io is the "batteries-included" choice (I'm a big fan and former contributor to the ecosystem - see tRPC-SvelteKit) but I always found the amount of boilerplate to be a bit discouraging for new developers and/or small projects. Telefunc looks like a nice alternative, but it doesn't (yet?) have an obvious way of integrating with the Next.js app router.

It would be nice to use server actions for RPC without the current limitation of being unable to call multiple functions in parallel.

Well, that's what next-server-actions-parallel is for.

How does it work?

The createParallelAction is simply wrapping the promise your server action returns in an array (a single-ellement tuple, to be more precise - see note below) and returning that array instead of the result of the promise.
The runParallelAction client-side utility function will simply await the promise and return the array element.

This repository contains a simple Next.js app that demonstrates it in action and benchmaks it against REST API routes and default server actions, so you can check it oun in different environments and decide if it makes sense for your project.

Note: Wrapping the promise in an object would also work, but I've chosen the array for data-transfer efficiency.

Do I actually need to use this library?

Not necessarily. The two functions that are exported by the library are small enough to be easily copied and pasted into your own project.
But since this is a common pain point for many developers, I've decided to provide a simple and easy-to-use wrapper. And hope that if you find it useful you won't hesitate to show your eternal gratitude by throwing a few greenbacks my way , at least for discovering the trick... 😜

License

The MIT License.