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

Middleware does not run before cached content is loaded

Open mgoodenough opened this issue 2 years ago • 6 comments

Verify canary release

  • [X] I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: x64
      Version: Darwin Kernel Version 22.2.0: Fri Nov 11 02:08:47 PST 2022; root:xnu-8792.61.2~4/RELEASE_X86_64
    Binaries:
      Node: 16.13.2
      npm: 8.1.2
      Yarn: N/A
      pnpm: N/A
    Relevant Packages:
      next: 13.4.14-canary.5
      eslint-config-next: N/A
      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)

Middleware / Edge (API routes, runtime)

Link to the code that reproduces this issue or a replay of the bug

https://github.com/mgoodenough/nextjs-middleware-caching

To Reproduce

Step 1: From the navigation menu on the Home page, click the Dashboard Link. Prior to page load, the middleware will log the following snippet to the console: pathname => /dashboard

Step 2: From the navigation menu on the Dashboard page, click the Home Link. Prior to page load, the middleware will log the following snippet to the console: pathname => /

Step 3: From the navigation menu on the Home page, click the Dashboard Link. Prior to page load, the middleware does not run.

Describe the Bug

When navigating from one page to another in the Next.js app via the Link component, middleware will only run on the first visit and will not run on subsequent visits to previously viewed (cached) pages.

Expected Behavior

When navigating from one page to another in the Next.js app via the Link component, middleware will run before cached content and routes are matched.

Which browser are you using? (if relevant)

Chrome Version 114.0.5735.133

How are you deploying your application? (if relevant)

No response

mgoodenough avatar Aug 14 '23 16:08 mgoodenough

Encountering the same issue, and the bug persists in the reproduction repository 👍🏻

Referring to the Next JS documentation :

Next.js has an in-memory client-side cache called the Router Cache. As users navigate around the app, the React Server Component Payload of prefetched route segments and visited routes are stored in the cache. This means on navigation, the cache is reused as much as possible, instead of making a new request to the server - improving performance by reducing the number of requests and data transferred.

Upon reviewing the documentation, it raises a concern. If cached route segments don't trigger a new request to the server, how does the middleware receive the request?

quentingrchr avatar Nov 30 '23 10:11 quentingrchr

Having the same issue. Is it possible to disable the cache? Even better can it be disabled just for specified 'protected' routes?

NickG-NZ avatar Jan 10 '24 23:01 NickG-NZ

Having the same issue in my project. Anyone have any best practice workaround/solution yet?

professor-oats avatar Feb 15 '24 18:02 professor-oats

Okay turns out the caching system is a big controversy with the app router. Long story short, currently the cache cannot be disabled and lasts for 30 seconds. If you call router.refresh() it clears the cache. Basically don't rely on middleware to protect page routes. Instead use a server component which wraps the protected page

NickG-NZ avatar Feb 15 '24 19:02 NickG-NZ

Interesting. I have router.refresh() inside the code when handling logout (hook) so a new sign-in will be possible and update the elements correspondingly.

In my case it still loads cached elements when making a new sign-in, after the first, but now I know it can rely either on where/when the router.refresh() is used or if I can change the conditions for the displayed elements somehow.

professor-oats avatar Feb 15 '24 20:02 professor-oats

Super thanks for your insight man. I started to fill some other parts of the code with router.refresh() after pushing a new route and now it works. MVP

professor-oats avatar Feb 15 '24 20:02 professor-oats

We hit the same issue when using OpenNext with NextJS 14.2.4, but interestingly not when using NextJS default FileSystem cache. I suspect that NextJS default caching is cleaning up the cache in its background job while OpenNext does not do that.

To me, the caching system does not matter as the middleware should kick in before the caching resolution.

This is documented as such on NextJS doc:

... Middleware runs before cached content and routes are matched. See Matching Paths for more details.

And this is documented on next-auth too:

You can use a Next.js Middleware with NextAuth.js to protect your site.

Next.js 12 has introduced Middleware. It is a way to run logic before accessing any page, even when they are static

arnaud-deprez avatar Jul 10 '24 15:07 arnaud-deprez

@arnaud-deprez I agree, the middleware should kick in before the caching system per the documentation you referenced, but in my experience (thus the reason I opened this issue) that was not happening. The middleware would not trigger on cached pages.

mgoodenough avatar Jul 10 '24 15:07 mgoodenough

There is a discussion going on too

arnaud-deprez avatar Jul 11 '24 07:07 arnaud-deprez

can we please fix this? This is causing my client so much trouble!

accountunavaible avatar Jul 17 '24 06:07 accountunavaible