next.js icon indicating copy to clipboard operation
next.js copied to clipboard

fix: patch fetch() signature instead of extending RequestInit

Open m1abdullahh opened this issue 1 week ago • 1 comments

Fixing a bug

What?

This PR changes how the next option (with revalidate and tags) is typed for fetch requests. Instead of extending the global RequestInit interface, we now only patch the fetch() function signature to accept NextFetchRequestInit.

Why?

Previously, extending the global RequestInit interface created a type mismatch with runtime behavior. When using new Request({ next: {...} }), JavaScript's native Request constructor drops any properties that aren't part of the standard RequestInit interface, so the next option would be silently ignored. This created confusion because TypeScript would allow it, but it wouldn't actually work at runtime.

By restricting the next option to only be available through fetch() calls, we:

  • Align TypeScript types with actual runtime behavior
  • Prevent users from trying to use next with new Request() where it won't work
  • Make the API more explicit about where the next option is supported

How?

  1. Removed global RequestInit extension in packages/next/types/global.d.ts

    • Removed the interface extension that added next?: NextFetchRequestConfig to all RequestInit types
  2. Created NextFetchRequestInit type and augmented only fetch()

    • Added NextFetchRequestInit interface extending RequestInit with the next property
    • Used declare global to augment only the fetch() function signature to accept NextFetchRequestInit
    • Added export {} to make the file a module (required for global augmentations)
  3. Updated patched fetch implementation in packages/next/src/server/lib/patch-fetch.ts

    • Updated function signature to use NextFetchRequestInit instead of RequestInit
    • Added local type definitions for consistency
    • Fixed TypeScript compatibility issues with newer fetch type definitions

Now next can only be passed through fetch(), not through new Request(), which matches the actual runtime behavior. Fixes #86898

m1abdullahh avatar Dec 11 '25 15:12 m1abdullahh

Allow CI Workflow Run

  • [ ] approve CI run for commit: 79bba26fe080f00e52a7f7d8d5633b41c61218ba

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

nextjs-bot avatar Dec 11 '25 15:12 nextjs-bot

Great fix! 👍

This approach is much cleaner than extending RequestInit globally. By patching the fetch() signature directly with NextFetchRequestInit, you're:

  1. ✅ Preventing the next option from leaking into non-Next.js fetch calls
  2. ✅ Maintaining proper TypeScript type safety
  3. ✅ Following the pattern of augmenting global scope in a module context

The implementation looks solid. The type casting in patch-fetch.ts is appropriate since we're intentionally narrowing the signature for Next.js-specific behavior.

One minor suggestion: Consider adding a JSDoc comment to NextFetchRequestInit explaining that this is Next.js's extended fetch signature, to help developers understand why it exists separately from the standard RequestInit.

Otherwise, LGTM! 🚀

harikapadia999 avatar Dec 13 '25 03:12 harikapadia999