Unexpected high serverless function usage on Vercel with Next.js App Router #89580
-
|
Hi everyone 👋 I’m running a Next.js (App Router) project on Vercel and noticed that my Serverless Function usage is much higher than expected, even though most of my pages should be cached. I’m trying to understand what might be causing this. Setup
What confuses meI assumed that after the first request, pages would be served from cache and wouldn’t keep invoking serverless functions. But Vercel analytics show functions running far more often than expected. Questions
If anyone has insights into this or debugging tips, I’d really appreciate the help. Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
|
Hi! This is a very common confusion with the App Router on Vercel. What usually happens is that something in the route is silently forcing it to be dynamic, so Vercel can’t serve it from the cache and has to run the Serverless Function on every request. The most common triggers are:
Any of these make the route SSR on every hit. How to verifyCheck the response headers in the browser:
How to fixMake sure your data fetching looks like this: await fetch(url, {
next: { revalidate: 60 },
});Avoid using You can also explicitly force static behavior: export const dynamic = 'force-static';Once the route becomes truly static/ISR, you’ll see function usage drop and Hope this saves you some function invocations |
Beta Was this translation helpful? Give feedback.
-
Without Cache Components on, pages are either, fully static, or fully dynamic. There isn't really a good in-between hybrid. A fully dynamic page gets to access latest data and such, but needs to be mindful of Suspense states to start pushing out UI to the browser as it renders to completion. A fully static page serves from CDN, immediately, but might have stale data. To try and marry these two ideas, ISR was introduced, a static page that regenerates itself, at runtime, given certain parameters. The key bit here is that fully dynamic page in the current model, is any page that access so-called dynamic data within its React tree. Dynamic data in this model are things such as cookies, searchParams, headers, etc - these are only known when a request arrives, so they can't be statically prerendered. There's also fetch, and the part that's a bit confusing in the current model, not-in-cache-components, that you can make fetch explicitly cached, or mark it as data that may be stale for a revalidate time, and that changes how the page behaves.
Yes. In Cache Components this nuanced and likely more close to what you'd expect.
The build output prints clearly which routes are fully static, dynamic, and such, each route gets an icon and the icon legend is printed at the bottom.
Depends on your use case. If you want to show financial info by the second, you are likely going to need to more frequent server function execution. If you are showing the list of the first 150 pokemon, you can statically render that on a page and that and cut your runtime server function execution to zero. |
Beta Was this translation helpful? Give feedback.
Hi! This is a very common confusion with the App Router on Vercel.
What usually happens is that something in the route is silently forcing it to be dynamic, so Vercel can’t serve it from the cache and has to run the Serverless Function on every request.
The most common triggers are:
cookies()orheaders()anywhere in the treefetchwithout proper caching configcache: 'no-store'export const dynamic = 'force-dynamic'(even indirectly)Any of these make the route SSR on every hit.
How to verify
Check the response headers in the browser:
x-vercel-cache: HIT→ served from cache…