Caching with App Route Handler
Answered
Singapura posted this in #help-forum
SingapuraOP
Hello. I'm trying to understand the caching in Route Handlers. I have a GET request here that always returns
X-Vercel-Cache: MISS, but I believe I have all the criteria to have it be cached by default. I'm using a GET request and I'm not using the Request, cookies, or headers.export async function GET(
_request: Request,
{ params }: { params: { race: string } }
) {
const raceId = Number(params.race)
const events = await prisma.raceEvent.findMany({
where: { raceId },
include: {
racer: true,
},
orderBy: { happenedAt: 'asc' },
})
return NextResponse.json(events)
}Answered by fuma
Only
And SQL queries aren't cached either if it's not using
GET route handlers will be statically cached by default, in your case, it's under a dynamic route which opts out of that.And SQL queries aren't cached either if it's not using
fetch41 Replies
Only
And SQL queries aren't cached either if it's not using
GET route handlers will be statically cached by default, in your case, it's under a dynamic route which opts out of that.And SQL queries aren't cached either if it's not using
fetchAnswer
SingapuraOP
is there anyway to specify to cache this route or to opt-in?
1. You can use
2. use
generateStaticParams to generate the routes in build time2. use
unstable_cache to cache the result of SQL queries, it's currently undocumented.To revalidate, you must use option 2.
SingapuraOP
i’m thinking i might try to wrap the prisma / sql call in a separate route and then use fetch to cache that
but you’re saying there is no way to cache a response for a dynamic route handler? what about using Cache-Control headers?
my goal is to have something like ‘/races/:id/events’ return cached JSON and stay heavily cached until it’s manually revalidated.
i was imaging it like ISR where i could statically have responses and then revalidate on demand
For now, you can't cache the response, but you can cache the result of queries with
Separating it into multiple routes can also fix the problem since it's not pre-rendered in build time.
unstable_cache.Separating it into multiple routes can also fix the problem since it's not pre-rendered in build time.
SingapuraOP
i was pretty sure you could specify a Cache-Control header on Vercel and that would put it in the Vercel Cache. is that not possible with the Next.js app router?
Yep, it's a Vercel feature.
Next.js doesn't support caching dynamic route handlers due to its design
Next.js doesn't support caching dynamic route handlers due to its design
SingapuraOP
okay, that makes sense. if i am deploying to Vercel, is there a way to cache dynamic route handlers on their platform or still not possible?
Here's what I've found: https://vercel.com/docs/concepts/edge-network/caching#using-vercel.json-and-next.config.js
Adding the header to your route should cache your response (only on Vercel)
SingapuraOP
yeah, this is what i had planned on doing.
* making a separate route handler for the database call
* use a route handler for public consumption w/ edge runtime + cache-control header
* making a separate route handler for the database call
* use a route handler for public consumption w/ edge runtime + cache-control header
btw first of all why do you need to cache the response of route handlers
SingapuraOP
the route handler provides a list of events for a race that is changing frequently. with quite a sizable audience watching live, i want to cache the results so it's very fast. when a new event happens, i want to revalidate the event list on-demand
after the revalidation occurs, a websocket is sent to the client requesting the new data.
I see, both the header solution and
I believe there will be new features for caching SQL queries soon, but currently just stay with the hacky solution
unstable_cache fits your use case I believe there will be new features for caching SQL queries soon, but currently just stay with the hacky solution

SingapuraOP
thanks for your help!
Long-toed Stint
Hey! I have pretty common setup with projects page and /project/[slug] route.
Each page is a server component and has default
When I add review I need to revalidate the project page and re-fetch data to get updated reviews. I've read github issue and looks like it doesn't work at all, am I right or missing something?
After review form submission I call
Can you please help me with advice here?
Each page is a server component and has default
const project = await fetch("/project/${params.slug}")When I add review I need to revalidate the project page and re-fetch data to get updated reviews. I've read github issue and looks like it doesn't work at all, am I right or missing something?
After review form submission I call
fetch(/api/revalidate?path=/project/test) and in api route I have a call revalidatePath(projectPath), but it works only once or doesn't work at all. I tried to put tags and call revalidateTag() also checked tags-manifest.json in next/cache to verify tags, but nothing...Can you please help me with advice here?
SingapuraOP
@Long-toed Stint are you using the pages router or the app route handlers?
Long-toed Stint
App router
SingapuraOP
i'm not really sure how to help, to be honest. i've had some flaky behavior when testing with tags
Long-toed Stint
True, dude. Im wonder if there is no option to handle simple route update on mutations like this
SingapuraOP
what i had tried was also
revalidateTag. i'll try and get a reproduction up later todaymy chain was essentially:
* on the client, call GET
* within
* when i create a new event (ie revalidate the tag), i perform my database call in a separate route handler then call
* the cache was always 1 event behind
* on the client, call GET
/races/:id/events (route handler running on edge)* within
/races/:id/events call GET /races/:id/events/origin (route handler running node). the origin route handlers calls prisma / database. since it's a fetch request, it is cached via tag race1Events.* when i create a new event (ie revalidate the tag), i perform my database call in a separate route handler then call
revalidateTag('race1Events')* the cache was always 1 event behind
i have a feeling this might be something i've implemented incorrectly vs it being a platform / framework issue
@fuma 1. You can use `generateStaticParams` to generate the routes in build time
2. use `unstable_cache` to cache the result of SQL queries, it's currently undocumented.
Sun bear
Would putting the sql query inside a dedicated route handler and calling that handler with fetch allow for caching?
Yes, though it’s not recommended, it works
@fuma Yes, though it’s not recommended, it works
Sun bear
Why is it not recommended?
People usually prefer putting in a Server component directly
@fuma People usually prefer putting in a Server component directly
Sun bear
I'd definitely prefer that as well however I really really need to cache the results of an SQL query, and revalidate on command. I'm getting like 100k row reads on some days rn and i'm desperately trying to stay within the free tier.
Yea I know, it’s frustrating that the docs didn’t mention any methods to cache something that’s not
fetch. We have cache for request memorisation, and unstable_cache which is not yet documented. For now, the only possibility I know is to static generate the page/route, but seems like revalidate has problems in new versions.So ISR isn’t even possible in the case. Although I got it work in my blog, many people had reported it isn’t working as expected.
Sun bear
Definately frustrating
SingapuraOP
so yesterday when i said "the cache was always 1 event behind" i figured out why, and it makes sense after thinking about it
the api being called is for
revalidateTag, which is what essentially invalidates the cache. this is the same thing as if you were setting a time-based value for revalidate and it expired. you are still served the static value while the updated version is being genereated.so even though
revalidateTag has been called, there's no way to know (from what i can see) that the cache for a tag is now done being rebuiltit would be really cool to see something like
regenerateCache available as an async API or a webhook, event, etc so that your application could know when the cache is done being regenerated