Next.js Discord

Discord Forum

Help: How to use revalidatePath with an overwritten dynamic route in the middleware

Unanswered
Cape lion posted this in #help-forum
Open in Discord
Cape lionOP
I'm not sure if I'm doing something wrong, or if I have a conceptual mistake, or if Next.js just doesn't work as I expected. I'm working on a project with many websites, each with its own domain, and I collect all the routes with a dynamic route per domain as the first parameter. To collect the domain as the first parameter, I have a middleware that transforms the host into the first parameter of the request.

The problem comes when I try to use revalidatePath specifying the route, as if it were already processed by the middleware. For instance, let's say I have a website test.com, and I execute revalidatePath('/test.com/testpage'), this has no effect on revalidating the page. However, if I execute revalidatePath('/testpage'), it does invalidate the cache, but it does so for all the websites in the project, not just test.com. This is a problem because the project has too many websites, leading to unnecessary processing expenditure.

It's worth mentioning that the project was in Next.js 12, and with the old "res.revalidate()" functionality, it only invalidated the cache of the route from where the request was made. That is, if you made a request to the API with the request https://test.local/api/revalidate, and in the controller, you had res.revalidate('/testpage'), it only invalidated the page of the test.local website; the rest remained cached.

Upon migrating to Next.js 14, we've encountered this issue, which is a pity because we've migrated our entire file structure to take advantage of all the new features. I reported this in the issues section https://github.com/vercel/next.js/issues/59825 but didn't receive a response.

Can anyone help me?
Thank you very much! Have a beautiful day 😄

62 Replies

Plott Hound
have you tried using revalidateTag instead?
@Cape lion I'm not sure if I'm doing something wrong, or if I have a conceptual mistake, or if Next.js just doesn't work as I expected. I'm working on a project with many websites, each with its own domain, and I collect all the routes with a dynamic route per domain as the first parameter. To collect the domain as the first parameter, I have a middleware that transforms the host into the first parameter of the request. The problem comes when I try to use revalidatePath specifying the route, as if it were already processed by the middleware. For instance, let's say I have a website test.com, and I execute revalidatePath('/test.com/testpage'), this has no effect on revalidating the page. However, if I execute revalidatePath('/testpage'), it does invalidate the cache, but it does so for all the websites in the project, not just test.com. This is a problem because the project has too many websites, leading to unnecessary processing expenditure. It's worth mentioning that the project was in Next.js 12, and with the old "res.revalidate()" functionality, it only invalidated the cache of the route from where the request was made. That is, if you made a request to the API with the request https://test.local/api/revalidate, and in the controller, you had res.revalidate('/testpage'), it only invalidated the page of the test.local website; the rest remained cached. Upon migrating to Next.js 14, we've encountered this issue, which is a pity because we've migrated our entire file structure to take advantage of all the new features. I reported this in the issues section https://github.com/vercel/next.js/issues/59825 but didn't receive a response. Can anyone help me? Thank you very much! Have a beautiful day 😄
can you describe your file structure vs the actual path you revalidate?
so you have smth like "[siteName]/testpage" with an actual instance being "test.com/testpage", "foobar.com/testpage" etc?
normaly you'd revalidate the "test.com/testpage" path indeed, it should revalidate only this page and not "foobar.com/testpage"
I don't get how you could revalidate "testpage" only, this doesn't make sense, the path must be complete relative the app dir
note that if you revalidate "[siteName]/testpage" it will revalidate all sites
which is expected, the possibility to revalidate only one route has been added in the latest versions of next 13 so normally it should work in Next 14
I don't think it's related to the middleware
unless your middleware has some kind of invalid matching that alters the revaldiation request or smth like that
@Plott Hound have you tried using revalidateTag instead?
Cape lionOP
Yes, I also tried revalidateTag and it didn't work. I had no way to create different tags for each site.
@Eric Burel can you describe your file structure vs the actual path you revalidate?
Cape lionOP
The directory path is as follows. I have the first level that dynamically collects the domain, and then [[…slug]] that collects the rest of the parameters of the request.



The thing is, when users access the web pages, they don't enter via https://domain.com/domain/slug, but instead, they enter https://domain.com/slug.

To collect the domain, we have a middleware that takes the host and rewrites the request to add it to the query parameters.

export default function middleware(req) {
  const url = req.nextUrl.clone()
  const { pathname } = req.nextUrl
  let hostname = req.headers.get('host').replace(/:\d+$/, '')

  if (!hostname) {
    return
  }

  url.pathname = `/${hostname}${pathname}`

  return NextResponse.rewrite(url)
}


When executing revalidatePath, if we do it in the following way revalidatePath('/test'), it invalidates the cache of all sites at the /test URL.

However, if we only want to revalidate the cache of domain.com/test, we have no way to do it. Since entering revalidatePath('/domain.com/test') has no effect.

In the following link, there is a repository with an example of the structure and middleware we use.
https://github.com/sergiolamorda/nextjs-issue-revalidatePath-multitenant

Thank you very much for responding!
You have to distinguish the route and the url
or the path and the url
basically what users see, and what's inside Next
the middleware allowing to decouple path and url via URL rewrites
what you want to invalidate is what is internal to Next.js
so for instance revalidatePath("/my-domain/testpage")
if you run "revalidatePath("/test")", to me you are invalidating everything under the "[domain]" of value "/test"
@Eric Burel what you want to invalidate is what is internal to Next.js
Cape lionOP
Of course, the problem is that when I make revalidatePath('/domain/slug'), it has no effect. The cache of the old version still remains.
hmm that could be related to having a rest param
did you try the layout mode too, to revalidate the layout and not just a specific page?
maybe smth like revalidatePath(/domain) with layout mode, so you revalidate a whole subsite but at least not all domains
@Eric Burel maybe smth like revalidatePath(/domain) with layout mode, so you revalidate a whole subsite but at least not all domains
Cape lionOP
The layout parameter only works when you use revalidatePath with a filesystem path, it doesn't work if it's a URL. Unfortunately, it still doesn't work... 😦
@Eric Burel hmm that could be related to having a rest param
Cape lionOP
I also tried removing the rest parameters and the cache still isn't invalidated.
maybe you meant applying on the segmented definition (eg ("[foobar]/hello") versus a specific path (eg "42/hello") ?
@Eric Burel maybe you meant applying on the segmented definition (eg ("[foobar]/hello") versus a specific path (eg "42/hello") ?
Cape lionOP
If I use revalidatePath('[domain]/hello') it revalidates all the domains, that's why it doesn't work for us.
@Cape lion If I use revalidatePath('[domain]/hello') it revalidates all the domains, that's why it doesn't work for us.
yes indeed, and then "revalidatePath("a-specific-domain/hello")" doesn't work right?
The thing is that it was a known bug
but only in older versions of Next
so perhaps it also happens in some buggy minor versions
normally it was solved in 13.5/14
that's because under the hood caching is done via complex system of tags and NExt.js couldn't yet handle dynamic tags (generating a "soft" tag for each specific value the [domain] param could take) but it has been added a few months ago
@Eric Burel yes indeed, and then "revalidatePath("a-specific-domain/hello")" doesn't work right?
Cape lionOP
Here's an example of what's happening to me.
My route structure is as follows:
[domain]/[[…slug]]

I execute revalidatePath('/test2.local')
| Browser                          | Result          |
|----------------------------------|-----------------|
| http://test1.local/test1.local   | Keeps cache     |
| http://test1.local/test2.local   | Invalidates cache |
| http://test2.local/test1.local   | Keeps cache     |
| http://test2.local/test2.local   | Invalidates cache |


If I execute revalidatePath('/test2.local/test2.local')
| Browser                          | Result          |
|----------------------------------|-----------------|
| http://test1.local/test1.local   | Keeps cache     |
| http://test1.local/test2.local   | Keeps cache     |
| http://test2.local/test1.local   | Keeps cache     |
| http://test2.local/test2.local   | Keeps cache     |


It should be noted that the middleware rewrites the parameters so that the browser correctly interprets the route structure of Next.js.
url.pathname = '/${hostname}${pathname}'

We are currently using version 14.0.4
I don't understand what could be happening, it seems like there might be a bug. What do you think?
@Cape lion sorry I still don't get why you'd involve the middleware here
if it has an impact, it's a bug
because revalidation happens after that, in the Next app
so the path your revalidate is unrelated to the URL
"revalidatePath('/test2.local/test2.local')" there is no reason for this to work
"revalidatePath('/test2.local')" this seems correct
@Eric Burel "revalidatePath('/test2.local')" this seems correct
Cape lionOP
I mean, with revalidatePath('/test2.local/test2.local'), the first "test2.local" refers to the domain, and the second refers to the slug. But this has no effect on the cache.
With revalidatePath('/test2.local'), I expect to revalidate the entire domain, but instead, it's revalidating /test2.local for all domains.
def smells like a bug, you'd want to craft a minimal reprodution
what version of Next are you using?
hmm I got an idea
maybe it's the router cache that is confused
if you open your page in another browser, is it still cached?
maybe the revalidate call only invalidate the server but not the client cache for the current user
because the URL seen by the browser would not be the same as the path used server-side after the middleware URL rewrite
that would be suprising but I don't know
if you disable the rewrite and access the relevant URLs manually, do you still have the issue?
basically you need to check if it's really the middleware URL rewrite that creates this issue or not
@Eric Burel what version of Next are you using?
Cape lionOP
I am using version 14.0.4 of Next
@Eric Burel maybe the revalidate call only invalidate the server but not the client cache for the current user
Cape lionOP
I have tried opening the page in another browser and the old version is still cached
@Eric Burel def smells like a bug, you'd want to craft a minimal reprodution
Cape lionOP
In the following link is the minimal reproduction. It includes the middleware, the file structure, and how to reproduce it. https://github.com/sergiolamorda/nextjs-issue-revalidatePath-multitenant
@Eric Burel At this point you'll want to open a github issue, I'll also take a look at your repro next week
Cape lionOP
Thank you very much, Eric. I opened an issue a couple of weeks ago, but I'm not sure if it has been taken into account or if it has gone unnoticed. Is there any way to confirm if the bug I reported is on the roadmap? https://github.com/vercel/next.js/issues/59825
@Cape lion I can indeed reproduce, I've posted a message and tweeted it maybe it'll help 🤷‍♂️ I need this approach a lot too so it's disappointing indeed