Next.js Cache
Unanswered
Chinese Alligator posted this in #help-forum
Chinese AlligatorOP
Hello everyone.
I am now working on Next.js project and I want to use cache.
And I want to clear the cache whenever I click "refresh" button to get refetched data.
Here is my script.
And here is clearing cache script.
The problem is that cache is not cleared and I am continuously getting the old data even though I tried to call the clearing cache api.
What is the reason and how can I clear that cache?
Thank you for your helping in advance.
I am now working on Next.js project and I want to use cache.
And I want to clear the cache whenever I click "refresh" button to get refetched data.
Here is my script.
import { NextRequest, NextResponse } from "next/server";
const BACKEND_URL = process.env.NEXT_PUBLIC_SERVER_URL!;
const ENDPOINT = "/utils/cache-example";
export async function GET(req: NextRequest) {
try {
const url = new URL(req.url);
const params = url.searchParams;
const backendParams = new URLSearchParams();
params.forEach((value, key) => {
backendParams.set(key, value);
});
const backendUrl = `${BACKEND_URL}${ENDPOINT}?${backendParams.toString()}`;
const res = await fetch(backendUrl, {
headers: { "Content-Type": "application/json", Authorization: req.headers.get("Authorization")! },
next: { revalidate: 3600, tags: ["cache-example"] },
});
const data = await res.json();
return res.ok
? NextResponse.json(data, {
headers: {
"Cache-Control": "public, s-maxage=3600, stale-while-revalidate=60",
"Vary": "Authorization",
},
})
: NextResponse.json(
{ error: data?.error || res.statusText },
{ status: res.status }
);
} catch (err: any) {
return NextResponse.json(
{ error: "Backend request failed", details: err.message },
{ status: 500 }
);
}
}And here is clearing cache script.
import { NextResponse } from "next/server";
import { revalidateTag } from "next/cache";
export async function POST() {
try {
const tags = [
"cache-example",
"cache-data",
];
tags.forEach(tag => revalidateTag(tag));
return NextResponse.json({
success: true,
message: "Cache cleared",
tags,
});
} catch (err: any) {
return NextResponse.json(
{
success: false,
error: err?.message || "Something went wrong",
},
{ status: 500 }
);
}
}The problem is that cache is not cleared and I am continuously getting the old data even though I tried to call the clearing cache api.
What is the reason and how can I clear that cache?
Thank you for your helping in advance.
5 Replies
Transvaal lion
Disclaimer: I am not expert in this topic, still trying to contribute
TL;DR: use updateTag in server action
AFAIK revalidateTag revalidates the data from data-cache only, your client-cache still is there in the browser and for that reason stale data will be displayed until you refresh the page or hit the GET route after hitting the revalidate route in the handleClick of refresh button.
So my best bet is that, instead of calling POST route handler, you call server action in handleClick and call updateTag there. This will purge the client cache and server cache both and also give the fresh data synchronously.
TL;DR: use updateTag in server action
AFAIK revalidateTag revalidates the data from data-cache only, your client-cache still is there in the browser and for that reason stale data will be displayed until you refresh the page or hit the GET route after hitting the revalidate route in the handleClick of refresh button.
So my best bet is that, instead of calling POST route handler, you call server action in handleClick and call updateTag there. This will purge the client cache and server cache both and also give the fresh data synchronously.
@Transvaal lion Disclaimer: I am not expert in this topic, still trying to contribute
TL;DR: use updateTag in server action
AFAIK revalidateTag revalidates the data from data-cache only, your client-cache still is there in the browser and for that reason stale data will be displayed until you refresh the page or hit the GET route after hitting the revalidate route in the handleClick of refresh button.
So my best bet is that, instead of calling POST route handler, you call server action in handleClick and call updateTag there. This will purge the client cache and server cache both and also give the fresh data synchronously.
Chinese AlligatorOP
Hi, @Transvaal lion
Thank you for your answering.
Can you check this script, please?
Here,
In this function, I call the server API like this and set state using the response.
And
Even though, I use server action or api, none of them are not clearing the cache.
Thank you for your answering.
Can you check this script, please?
const refreshData = async () => {
try {
setIsLoading(true);
// await clearCache();
await refreshData();
await fetchFilteredData();
} catch (error) {
setIsLoading(false);
}
};Here,
fetchFilteredDatais the function to get the data from api.In this function, I call the server API like this and set state using the response.
export async function fetchKpiEngineers() {
try {
const token = getToken();
const query = new URLSearchParams({
optionId: "Open",
}).toString();
const res = await fetch(`/api/utils/cache-example?${query}`, {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
});
if (!res.ok) throw new Error("Failed to fetch data");
return await res.json();
} catch (err) {
console.error(err);
return [];
}
}And
refreshData is called when I click refresh button.clearCache is the api already shared and refreshData is server action what you mentioned."use server";
import { revalidateTag } from "next/cache";
export async function refreshData() {
revalidateTag("kpi-engineer");
}Even though, I use server action or api, none of them are not clearing the cache.
You are mixing two different cache layers:
Next.js Data Cache from this line:
HTTP/CDN/browser response cache from this line:
revalidateTag("cache-example") only invalidates the Next.js tagged Data Cache
It doesn't clear a CDN/shared HTTP cache that was created by Cache-Control: public, s-maxage=3600
Next.js Data Cache from this line:
next: { revalidate: 3600, tags: ["cache-example"] }HTTP/CDN/browser response cache from this line:
"Cache-Control": "public, s-maxage=3600, stale-while-revalidate=60"revalidateTag("cache-example") only invalidates the Next.js tagged Data Cache
It doesn't clear a CDN/shared HTTP cache that was created by Cache-Control: public, s-maxage=3600
Also, because your response depends on Authorization, you probably should not use public cache for this response. Even with Vary: Authorization, it is safer to avoid public shared caching for authenticated API responses
Transvaal lion
I have tried to reproduce your scenario to purge the client cache immediately after revalidating.
But the problem is on first click refresh button revalidates the cache from data cache and returns the stale data. Server in background refreshes the data.
On second click, server returns the fresh data.
I tried to purge the client cache after the first click itself using updateTag and router refresh, but still it is not working. I am not understanding the updateTag behaviour for client component. If you use server Component to fetch data, updateTag syncs the UI also immediately, but unfortunately client component are showing exception. Maybe someone can enlighten this behavior.
So apart from server component solution, this is working for me.
1. Remove the Cache control
2. in server action, call updateTag() and then refresh()
Hope someone can give proper solution for this
But the problem is on first click refresh button revalidates the cache from data cache and returns the stale data. Server in background refreshes the data.
On second click, server returns the fresh data.
I tried to purge the client cache after the first click itself using updateTag and router refresh, but still it is not working. I am not understanding the updateTag behaviour for client component. If you use server Component to fetch data, updateTag syncs the UI also immediately, but unfortunately client component are showing exception. Maybe someone can enlighten this behavior.
So apart from server component solution, this is working for me.
1. Remove the Cache control
2. in server action, call updateTag() and then refresh()
Hope someone can give proper solution for this