{"id":21847905,"url":"https://github.com/icflorescu/next-server-actions-parallel","last_synced_at":"2025-04-14T13:34:01.176Z","repository":{"id":264529433,"uuid":"893607526","full_name":"icflorescu/next-server-actions-parallel","owner":"icflorescu","description":"A small utility library that enables you to execute Next.js server actions in parallel - the missing ingredient to build a boilerplate-free tRPC-style server-actions workflow.","archived":false,"fork":false,"pushed_at":"2025-01-09T15:41:34.000Z","size":225,"stargazers_count":36,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-06T01:03:29.597Z","etag":null,"topics":["concurrency","concurrent","nextjs","non-blocking","parallel","react","rpc","server-actions"],"latest_commit_sha":null,"homepage":"https://next-server-actions-parallel.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/icflorescu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-24T21:35:34.000Z","updated_at":"2025-04-04T21:34:52.000Z","dependencies_parsed_at":"2024-11-24T21:57:38.270Z","dependency_job_id":"44be9904-d473-4f5d-a907-bc457e2f4856","html_url":"https://github.com/icflorescu/next-server-actions-parallel","commit_stats":null,"previous_names":["icflorescu/next-server-actions-parallel"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icflorescu%2Fnext-server-actions-parallel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icflorescu%2Fnext-server-actions-parallel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icflorescu%2Fnext-server-actions-parallel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icflorescu%2Fnext-server-actions-parallel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/icflorescu","download_url":"https://codeload.github.com/icflorescu/next-server-actions-parallel/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248888978,"owners_count":21178140,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","concurrent","nextjs","non-blocking","parallel","react","rpc","server-actions"],"created_at":"2024-11-27T23:20:07.885Z","updated_at":"2025-04-14T13:34:01.160Z","avatar_url":"https://github.com/icflorescu.png","language":"TypeScript","funding_links":["https://github.com/sponsors/icflorescu"],"categories":[],"sub_categories":[],"readme":"# Parallel Next.js Server Actions\n[![NPM version][npm-image]][npm-url]\n[![License][license-image]][license-url]\n[![Sponsor the author][sponsor-image]][sponsor-url]\n\nRun multiple Next.js server actions in parallel.  \n\n\u003e The missing ingredient to build [tRPC](https://trpc.io)-like workflows, but without the boilerplate.\n\n## TL;DR\n\nInstall:\n\n```sh\npnpm i next-server-actions-parallel\n```\n\nDefine your server actions like so:\n\n`app/page.actions.ts`:\n\n```ts\n'use server';\n\nimport { createParallelAction } from 'next-server-actions-parallel';\n\nexport const listUsers = createParallelAction(async () =\u003e { // 👈 don't forget the `async` keyword!!\n  return prisma.user.findMany(); // 👈 let's assume this takes 3 seconds\n});\n\nexport const listProducts = createParallelAction(async (categoryId: string) =\u003e {\n  return prisma.product.findMany({ where: { categoryId } }); // 👈 let's assume this also takes 3 seconds\n});\n```\n\nCall them like so:\n\n`app/page.tsx`:\n\n```ts\n'use client';\n\nimport { runParallelAction } from 'next-server-actions-parallel';\nimport { listUsers, listProducts } from './page.actions';\n\nexport default async function Page() {\n  // 👇 this may take slightly more than 3 seconds, but a lot less than 6.\n  const [users, products] = await Promise.all([\n    runParallelAction(listUsers()),\n    runParallelAction(listProducts('82b2ab20-ec1e-4539-85a2-ea6737555250')),\n  ]);\n\n  return (\n    \u003cdiv\u003e\n      \u003cul\u003e\n        {users.map((user) =\u003e (\n          \u003cli key={user.id}\u003e{user.name}\u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n      \u003cul\u003e\n        {products.map((product) =\u003e (\n          \u003cli key={product.id}\u003e{product.name}\u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n## How does it perform?\n\nIn a nutshell: a lot faster than default Next.js server actions, not as fast as REST API routes.  \nCheck it in your specific deployment environment and decide if it makes sense for your project.\n\n## Show gratitude\n\nIf you find [my open-source work](https://github.com/icflorescu) useful, please consider sponsing me on [GitHub Sponsors](https://github.com/sponsors/icflorescu).\n\n## Background story\n\nWhen 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](https://trpc.io) or [Telefunc](https://telefunc.com).\n\nMany were, however, disappointed to find that Next.js server actions were only executed in series, contrary to what one would expect when triggering them in parallel with `Promise.all`.  \nIt probably worked like that because they were intended to be used for mutations, as _\"data should be fetched in server components or using REST API endpoints\"_.  \nPlus, since server actions are implemented with `POST` requests, some purists are reluctant to the idea of using them for fetching data, though `POST` requests **can** and usually **do** return data.\n\nHowever, there are many reasons why projects like [tRPC.io](https://trpc.io), [Telefunc](https://telefunc.com) and other *RPCs were built and have no problem using `POST` requests to fetch data. If you're **building real, data-rich applications**, including something like [tRPC.io](https://trpc.io) in your stack gives you type-safety and spares you the effort of building and maintainings maybe hundreds of API endpoints just to populate dynamic UI components (such as autocompletes and selects).\n\n[tRPC.io](https://trpc.io) is the \"batteries-included\" choice; I'm a big fan and former contributor to the ecosystem - see [tRPC-SvelteKit](https://icflorescu.github.io/trpc-sveltekit/), but I always found the amount of boilerplate to be a bit discouraging for new developers and/or small projects. [Telefunc](https://telefunc.com) looks like a nice alternative, but it doesn't (yet, as of November 2024) have an obvious way of integrating with the Next.js app router.\n\nIt would be nice to use server actions for RPC without the current limitation of being unable to call multiple functions in parallel.  \nHere's a non-exhaustive list of issues and discussions where the subject was mentioned:\n- [https://github.com/vercel/next.js/discussions/50743](https://github.com/vercel/next.js/discussions/50743)\n- [https://github.com/vercel/next.js/issues/69265](https://github.com/vercel/next.js/issues/69265)\n- [https://x.com/cramforce/status/1733240566954230063](https://x.com/cramforce/status/1733240566954230063)\n- [https://stackoverflow.com/questions/77484983/why-are-server-actions-not-executing-concurrently](https://stackoverflow.com/questions/77484983/why-are-server-actions-not-executing-concurrently)\n- [https://stackoverflow.com/questions/78548578/server-actions-in-next-js-seem-to-be-running-in-series](https://stackoverflow.com/questions/78548578/server-actions-in-next-js-seem-to-be-running-in-series)\n\nWell, that's what [next-server-actions-parallel](https://github.com/icflorescu/next-server-actions-parallel) is for.\n\n## How does it work?\n\nIt's actually quite simple:\n\n- The `createParallelAction` is 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.  \n- The `runParallelAction` client-side utility function will await the promise and return the result.\n\nThis repository contains a light Next.js app that demonstrates it in action and benchmaks it against REST API routes and default server actions, so you can check it out in different environments and decide if it makes sense for your project.\n\n[Check it on StackBlitz ⚡️](https://stackblitz.com/~/github.com/icflorescu/next-server-actions-parallel)  \n[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Ficflorescu%2Fnext-server-actions-parallel)  \n\n_Note:_  \nWrapping the promise in an object would also work, but I've chosen to use an array for data-transfer efficiency.\n\n## Do I actually need to use this library?\n\nNot necessarily. The two functions that are exported by the library are small enough to be easily copied and pasted into your own project, see [source code here](https://github.com/icflorescu/next-server-actions-parallel/blob/main/src/index.ts).  \nBut since this is a common pain point for many developers, I've decided to provide a simple and easy-to-use wrapper... And maybe hope that if you find it useful you won't hesitate to show your eternal gratitude by [throwing a few greenbacks my way](https://github.com/sponsors/icflorescu), at least for discovering the trick... 😜\n\n## Acknowledgements\n\nMany thanks to [Will Koehler](https://github.com/willkoehler) for being the first person to support this project.\n\n## License\n\nThe [MIT License](LICENSE).\n\n[npm-url]: https://npmjs.org/package/next-server-actions-parallel\n[license-url]: LICENSE\n[sponsor-url]: https://github.com/sponsors/icflorescu\n[npm-image]: https://img.shields.io/npm/v/next-server-actions-parallel.svg?style=flat-square\n[license-image]: http://img.shields.io/npm/l/next-server-actions-parallel.svg?style=flat-square\n[sponsor-image]: https://img.shields.io/badge/sponsor-violet?style=flat-square\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficflorescu%2Fnext-server-actions-parallel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficflorescu%2Fnext-server-actions-parallel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficflorescu%2Fnext-server-actions-parallel/lists"}