How can I reduce my Serverless Execution usage on Vercel?

When deploying a project to Vercel, it is critical to abide by the fair use guidelines or your Enterprise agreement (email your Customer Success Manager for further information). The Usage Dashboard is the most important page to check the usage of your projects. Another useful tool to monitor requests and errors is the Function Logs tab as it can provide logging output for your Serverless Executions.

Definitions

Before we outline possible solutions for high usage of Serverless Functions, we need to define a few concepts that are relevant.

  • Serverless Invocation: When a Serverless Function is triggered by an event. Those events are typically requests that will be processed by the function.
  • Serverless Execution: The process of executing a Serverless Function, which is triggered by an invocation.
  • Serverless Function memory: The size of the memory allocated to the function. For further information, you can refer to the Configuration Reference.
  • GB-Hrs: The unit of measurement for Serverless Execution. If one function with 1024MB allocated takes one second to process a request, we can conclude it used 1GB-Seconds, which is (1/3600)GB-Hrs. For further information, check the article "What are GB-Hrs for Serverless Function Execution?".

With Next.js

Next.js is a framework that gives your team the flexibility to choose between different rendering methods:

  • Static Site Generation (SSG) allows you to generate static content at build time. Used through getStaticProps inside of Next.js.
  • Incremental Static Regeneration (ISR) allows you to create or update content without redeploying your site. Used through getStaticProps and revalidate inside of Next.js.
  • Server-Side Rendering (SSR) allows you to render pages dynamically on the server. This is useful for pages where the rendered data needs to be unique on every request. Used through getServerSideProps inside of Next.js.

It's possible to reduce your Serverless Function usage with all the rendering methods above. Even API Routes can use the Vercel CDN to cache responses and serve content directly from the edge for optimal speed.

Static Site Generation

If your page can use SSG instead of SSR, it is recommended that you implement this approach to lower the usage of Serverless Executions. The page will be generated a single time at build-time, and it is not possible to regenerate it or replace its content after the build. Since your app will no longer execute a function for every page request, which is true for uncached SSR pages, the amount of Serverless Executions for pages using SSG is 0 GB-Hrs.

Incremental Static Regeneration

In case a specific page needs to be regenerated periodically due to dynamic data, you can use ISR to lower the number of Serverless Executions performed by your app. With this strategy, your pages will be statically generated and cached in the Vercel CDN. A Serverless Function will be triggered after a certain interval to refresh the content of the cache. By using ISR, you will lower the amount of Serverless Executions used by your app in comparison with uncached SSR pages. Your users will also benefit from the speed improvements that ISR will give since your deployment will serve content directly from the Vercel CDN.

CDN Caching and stale-while-revalidate

If you are unable to implement ISR or SSG, you can use caching headers to store SSR pages in the Vercel CDN. One of the best headers is stale-while-revalidate, which is used to serve stale content while the cache is refreshed in the background. You can see an example of the header being used in a Next.js SSR page below. Do notice you can also use this header for Next.js API routes. If you need to apply the header to multiple paths, using the Next.js headers configuration is also an option.

export async function getServerSideProps(context) {
const res = await fetch(`https://...`)
const data = await res.json()
context.res.setHeader('Cache-Control', 's-maxage=600, stale-while-revalidate=30') // set caching header
return {
props: {}, // will be passed to the page component as props
}
}
A Next.js page using stale-while-revalidate.
export default function handler(req, res) {
res.setHeader('Cache-Control', 's-maxage=600, stale-while-revalidate=30') // set caching header
res.status(200).json({ name: 'John Doe' })
}
A Next.js API route using stale-while-revalidate.
next.config.js
module.exports = {
async headers() {
return [
{
source: '/example/:id',
headers: [
{
key: 'cache-control',
value: 's-maxage=600, stale-while-revalidate=30',
},
],
},
]
},
}
Applying a cache-control header to a path by using the Next.js headers configuration.

In the example above we are telling the Vercel CDN the content is fresh for 600 seconds, and it may continue to be served stale for up to an additional 30 seconds while an asynchronous validation is attempted by triggering a Serverless Function. If validation is inconclusive, or if there is not traffic that triggers it, after 30 seconds the stale-while-revalidate function will cease to operate, and the cached response will be "truly" stale (i.e., the next request will block and be handled normally).

Generally, you may want to use a combination of s-maxage and stale-while-revalidate to the longest total potential freshness lifetime that they can tolerate. For example, with both set to 600, the server must be able to tolerate the response being served from cache for up to 20 minutes. Since asynchronous validation will only happen if a request occurs after the response has become stale, but before the end of the stale-wile-revalidate window, the size of that window and the likelihood of a request during it determines how likely it is that all requests will be served without delay. If the window is too small, or traffic is too sparse, some requests will fall outside of it, and block until the deployment can validate the cached response.

The text above was inspired by RFC5681.

With Serverless Functions in /api

If you are not using Next.js, you can still implement some strategies to lower the amount of resources used by your deployment.

CDN Caching and stale-while-revalidate

If your API is returning data that can be shared publicly (without authorization headers or cookies), you can use caching headers to cache the response of the function in the Vercel CDN. One header that we can highlight is stale-while-revalidate.

module.exports = (req, res) => {
res.setHeader('Cache-Control', 's-maxage=600, stale-while-revalidate=30') // set caching header
res.status(200).json({ name: 'John Doe' })
}
An API Serverless Function with caching headers applied.

Configuring your Serverless Functions

You can customize the region, memory, and duration of your Functions.

{
"functions": {
"api/example.js": {
"memory": 128,
"maxDuration": 10
}
}
}
A Serverless Function using 128MB of memory and timing out after 10 seconds.
  • Memory: If your function is I/O bound and needs to wait on upstream providers often, lowering the memory size allocated to it is a good strategy to reduce the overall GB-Hrs used by your deployment. You should note that the CPU power of your Serverless Executions is directly related to the amount of memory configured to your functions. Therefore, for processing-intensive functions, lowering the memory size is not advised.
  • Region: Another important configuration is the Regions for your Serverless Functions. If you don't deploy close to upstream dependencies or providers, it is possible that the response time of your functions is being affected by latency. By deploying closer to your Database or API, you will observe that your functions will take lower to process a request, reducing your Serverless Executions usage overall.
  • Duration: By default, Vercel sets the duration of your Serverless Functions to 10 seconds for Hobby, and 15 for Pro and Enterprise. This lower default helps ensure your Functions don't unnecessarily run for a long time without returning a response. You can adjust it through the maxDuration config.
  • Runtime: Serverless Functions usually use the Node.js runtime (although can use Ruby, Python, Go, or any supported community runtime). Depending on your use case, using the Edge runtime may provide a more cost-effective option. Edge Functions automatically execute in the region nearest to the user who triggers them, but this may be far from your data source. See the runtime comparison for more information on deciding which runtime is best for your needs.

Couldn't find the guide you need?