next.js: Top level await (experimental) not working with Server Actions called from Client Components
Verify canary release
- I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 22.5.0: Thu Jun 8 22:22:20 PDT 2023; root:xnu-8796.121.3~7/RELEASE_ARM64_T6000
Binaries:
Node: 20.5.1
npm: 9.8.0
Yarn: 1.22.19
pnpm: N/A
Relevant Packages:
next: 13.4.19
eslint-config-next: 13.4.19
react: 18.2.0
react-dom: 18.2.0
typescript: 5.1.6
Next.js Config:
output: N/A
Which area(s) of Next.js are affected? (leave empty if unsure)
Link to the code that reproduces this issue or a replay of the bug
https://github.com/k-allagbe/my-app-canary.git
To Reproduce
- Run “npm run dev”
- In the web page, click “Upload” to call the server action
- result: error SyntaxError: await is only valid in async functions and the top level bodies of modules
Describe the Bug
The provided code is an example of using Top Level Await in a file containing Server Actions called from a Client Component. This is relevant because, my actions might depend on frameworks that use top level awaits.
The result shows that calling Server Actions from Client Components doesn’t work when the Server Action file involves top level await.
The problem is not observed with Server Components.
Expected Behavior
I expected to be able to call my Server Action from a Client Component even if a Top Level Await is involved in the Server Action file, because I might use some frameworks that rely on Top Level Awaits.
Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
No response
About this issue
- Original URL
- State: open
- Created 10 months ago
- Reactions: 20
- Comments: 21 (1 by maintainers)
I am also facing the same issue.
I’m using SST and have the same problem and this worked as well (Thank you!), but it’s ugly as hell. Hope this gets fixed soon.
I have fixed this by doing the following:
It’s a dirty workaround, but until it gets fixed you can do that. I think that’s what @adrienbaron was suggesting.
I have tons of server actions depends on that one top level await (db connection), so I don’t think adding init functions for every one of them is not going to be easy. Is there any plans to solve this issue in soon future?
I am facing the same error when working with Server Actions on Next 14.0.4 and SST. Does Next.js have a plan to support top level await in server actions in the near time?
You shouldn’t use top level await entirely. The case for using it is to initialize DB connections, that could be done in the hook calling some
init()function.@mordechaim some libraries, like Drizzle ORM or SST use top level await in their own code though, the issue occurs because of this, not top level await in my own application code (I don’t have any). Top level await is a standard JS feature these days, and Next supports it in most places, so it not being supported in this case feels more like a bug 🤷♂️.
I’m also facing this issue. I think it’s quite an essential demand to use top level await for initializing databases. Hope Next.js could fix this problem sooner.
One way to solve this, is to create one async function called eg. initActions and place every initializer inside, and only call initActions in eg. layout component. That way its easier to maintain IMO.
Here is the example code that I am using:
src/app/_initActions.ts
and in my src/app/layout.tsx
This totally worked and fixed the issue I’ve been spending hours working around. Thanks!
This seems to be fixed with Next.js 14.0.4 🎉!
EDIT: Spoke too fast, I can still reproduce on Next.js 14.0.4.
For people that get stuck with this, I had the same issue using SST and Drizzle in a Server Action called client side (both have top level awaits). Fixed it by simply importing my actions file from a server component:
I’m assuming this loads the module already on the server and means the top level await doesn’t happen inside the code path that’s broken? Not sure if it will actually work when deployed on Lambda though 😅
Any development on this? We need to make all our forms request a REST API, because our DB library has top level awaits. Is there any known workaround?
I’d like to point out that we could use the instrumentation API to initialize DB connections. That may solve most use cases for top level await.
Ok, tried deploying on AWS using SST with this trick and it actually does work 👍, even when the lambda is cold, calling the action from the client doesn’t crash, as long as the action module has been imported from a server component somewhere.
Would still feel like this should be fixed in Next.js (as in top level await should work in Server Actions called from client components out of the box)
Please keep in mind that top level await is currently an experimental feature of Next.js, and we will be working on making it more stable in the future 👍