-
Notifications
You must be signed in to change notification settings - Fork 70
Description
Describe the bug
When using initOpenNextCloudflareForDev
in next.config.ts
, running the next typegen
command hangs Node - a couple of active strong handles on the Node process are preventing it from stopping like it does in Vanilla Next.
This is somewhat fixed by Next in this commit which gracefully terminates the process via .exit
(just like next build
) - not released in npm yet.
However, the issue is still present in other next
commands (such as next info
).
I have a couple thoughts to share that I believe are relevant for this issue.
Does the initOpenNextCloudflareForDev
function actually needs to be called unconditionally in next.config.ts
?
The following code does resolve the issue and does not cause any hanging in other commands:
if (process.env.NODE_ENV === "development") initOpenNextCloudflareForDev()
It could technically reduce the probability of an unwanted side-effect to make its way onto other parts / lifecycles / commands of Next since it would only be called on development machines.
I'm not sure if this is actually desirable as I'm not very familiar with that process - it could be useful in other contexts than next dev
that I'm not aware of, which is why this is an issue rather than a PR.
Could it be possible to dereference the handles created by getCloudflareContextFromWrangler
?
From what I understand and tested, it appears the active blocking handles are mostly related to miniflare
workers and their implementation. All remaining Next handles are directly caused by this call.
If it is possible to prevent those handles from blocking Node altogether, it shouldn't block the Node process to behave like a regular Node process would - effectively ignoring the CF side-effect for the runtime.
I was able to confirm this by explicitly calling the returned getCloudflareContextFromWrangler(...).ctx.dispose()
function after a 10s delay (next typegen
reports its success after 3s in my test repo).
When dispose()
completes, the process does terminates gracefully, confirming that Miniflare (initialized by Wrangler) is indeed the root cause of the hang.
This behavior was also confirmed by introducing a simple, unrelated side-effect (setTimeout(() => {}, 20000)
in next.config.ts
).
In this scenario, the process only exits after both the setTimeout
finishes, which happens after the completion of getCloudflareContextFromWrangler(...).ctx.dispose()
, confirming that the Cloudflare context actually is what's blocking the process from finishing.
I'm not entirely sure if a solution can be implemented without relying on hacky workarounds (like polling handles using the private process._getActiveHandles
method) unless the underlying miniflare handles can be unref()
'd by default.
I probably miss a lot of knowledge and context - hope this could still help somehow, or at least give some more context in the repo.
Not entirely sure what to expect from this issue, also hope it's not going too far nor too wrong. Sorry if it is!
Steps to reproduce
-
Create an OpenNext CF project by following the instructions on https://opennext.js.org/cloudflare
-
Run
next typegen
-
The command should hang on
β Route types generated successfully
Expected behavior
The command should not hang.
@opennextjs/cloudflare version
1.9.1
Wrangler version
4.40.3
next info output
Operating System:
Platform: linux
Arch: x64
Version: #1 ZEN SMP PREEMPT_DYNAMIC Thu, 25 Sep 2025 17:17:10 +0000
Available memory (MB): 32034
Available CPU cores: 12
Binaries:
Node: 24.5.0
npm: 11.5.1
Yarn: 1.22.22
pnpm: 10.16.1
Relevant Packages:
next: 15.5.4 // Latest available version is detected (15.5.4).
eslint-config-next: N/A
react: 19.1.0
react-dom: 19.1.0
typescript: 5.9.3
Next.js Config:
output: N/A
Additional context
No response