Skip to content
Docs

Troubleshoot and optimize Function Invocations on Vercel

Diagnose which routes drive Function Invocations and learn to optimize them. Separate necessary dynamic traffic from divertible requests, fix common invocation patterns, and verify the change after shipping.

Mike DarlingtonDev Success Engineer

This guide investigates rising Function Invocations from a billing and usage perspective. If your invoice or the Usage page shows the number climbing, common causes include a route that opted into dynamic rendering unexpectedly, prefetch or bot traffic you didn't intend to serve, a client polling an API more often than the product needs, or uploads routed through a Function.

Under Fluid compute, a request that reaches a Function is an invocation, and you're billed per invocation, whether the Function succeeds or fails. A page built at deploy time is served from the CDN, so its requests never reach a Function and create zero invocations. That asymmetry is the playbook. First, find which routes requests are reaching. Second, divert the requests that don't need a Function. Serve them from the CDN cache, stop prefetch and bot traffic you don't want, quiet chatty clients, and move payloads out of the Function path.

In this guide, you’ll learn how to:

  • Confirm the rising metric is Function Invocations, not Middleware invocations or CDN Requests
  • Find the routes driving Function Invocations
  • Decide how each route should serve
  • Fix the most common invocation-heavy patterns
  • Run a safe, read-only agent investigation
  • Verify a change after shipping

Copy link to headingBefore you begin

Choose the scope you want to investigate:

  • Team
  • Project
  • Environment
  • Increase window
  • Comparison window
  • Recent deployment or release window, if known

Use the same scope throughout the investigation. Comparing different environments, routes, or time windows can make traffic changes look like billing changes.

Copy link to heading1. Confirm the usage source

In the dashboard, select the team and open the Usage page. Navigate to Functions → Function Invocations. The Count view shows the total amount of invocations across your projects.

Confirm you’re looking at the right metric before going route-level: Middleware invocation counts appear in a separate Middleware observability tab rather than the Vercel Functions tab, and if you suspect automated traffic, the CDN Requests observability surface has bot and bot-category breakdowns.

Copy link to heading2. Find the routes driving invocations

For project-level investigation, go to Observability → Vercel Functions. This view allows you to rank routes by invocations and drill into a specific route’s count and latency distribution. Follow the Observability route drill-down guide to identify which routes are driving your usage.

Open Observability → New Query and navigate to Visualize → Function Invocations to analyze usage with more precision. Query supports Count, Count per Second, and Percentages for this metric. You can group or filter by route, request path, cache result, request method, referrer URL, client IP, and client user agent. Full Query access requires Observability Plus, available on Enterprise and Pro plans. With free observability you can open a query, but modifying filters or creating new queries needs the subscription. Without it, the Vercel Functions view above covers route-level ranking.

For example, suppose the Usage page shows 20.9K invocations this week, and Query grouped by route attributes 9.1K of them, about 43.5%, to /api/factory, almost all with a cache result of MISS. Cache status is returned on every response in the x-vercel-cache header and appears as the cache result dimension in Query. That one route is your optimization target: an API endpoint polled by every open tab is a caller problem, and a dynamic page that could tolerate sixty seconds of staleness is a caching problem. The next step separates the two.

Copy link to heading3. Interpret the pattern

For each high-volume route, ask how its response varies, then pick the serving model that matches:

How the response variesServe it viaEffect on invocations
Same for everyoneStatic site generationZero: no Function runs per request
Changes on a schedule or when your data changes, tolerates brief stalenessISR, time-based or on-demand revalidationCached responses serve without invoking; revalidations still run the Function
Dynamic, but briefly cacheableCache-Control headers on the responseRepeat requests become CDN HITs and don’t invoke
Genuinely per-user or per-requestStays dynamicReduce the requests themselves. See prefetch, bots, chatty clients below

Copy link to heading4. Common causes and fixes

Copy link to headingCaching and dynamic rendering

The cache-status values tell you what each request did:

  • HIT serves the response without invoking a Function, and an ISR cache hit behaves the same way.
  • STALE serves the cached response immediately while a Function is re-invoked in the background.
  • BYPASS, such as one triggered by Draft Mode or a bypass token, skips the cached prerender and invokes a Function for a fresh response.
  • MISS can generate a response from a Function or from an origin, so a MISS alone does not prove which one ran.

ISR reduces invocations by serving cached content, but the Function still runs during background or on-demand revalidation. For simultaneous requests to the same uncached ISR path, Vercel collapses the misses into one Function invocation per region.

For Next.js App Router, identify your rendering model to avoid unexpected dynamic execution:

  • Classic model (pre-Cache Components): Using cookies(), headers(), or the page searchParams prop opts the entire route into dynamic rendering. Uncached fetch calls or revalidate: 0 also make the route dynamic.
  • Cache Components (Next.js 16): These APIs do not automatically opt the whole route into dynamic rendering. You can place request-time work behind Suspense to preserve a prerendered shell. Applying use cache to both the layout and page can prerender the entire route. Cache Components and use cache were unified under the stable cacheComponents model in Next.js 16.0.

Upgrade Note: In Next.js 14, GET Route Handlers were cached by default. Starting in Next.js 15, the default changed to dynamic, review GET handlers that relied on the old static default.

Note on Data Cache: In current Next.js, the Data Cache and Vercel Runtime Cache store data fetched during Function execution, and are distinct from the full-response CDN cache.

Copy link to headingRequest amplification and RSC traffic

Traffic volume can rise unexpectedly due to framework prefetching and React Server Component (RSC) requests: navigations and prefetches fetch server-rendered payloads for the destination route, so they show up in Query as additional requests against that route’s path, distinct from full page loads. Requests served from the CDN cache do not reach the Function.

On the App Router, prefetch behavior depends on the route and its rendering mode, and setting prefetch={false} on a <Link> disables viewport and hover prefetching. Where traced prefetch traffic is unnecessary, disable or narrow prefetching. Prefetching exists to make navigation feel instant, so narrowing it trades some navigation speed for fewer requests. Because the volume depends on the route and its rendering mode, measure it on your own routes rather than estimating it.

Copy link to headingAutomated traffic and bots

Automated clients can concentrate requests on dynamic routes. Vercel documents bot and bot-category breakdowns in the CDN Requests observability surface. That breakdown is not scoped to traffic that reached a Function, so attribute Function traffic by route, method and user agent in Query instead. For information on blocking unwanted traffic, see the Vercel Firewall and Bot Management documentation.

Copy link to headingChatty application endpoints

Internal API, auth, or session routes may receive more calls than required by product behavior. Redundant polling or refresh calls drive up costs because every one of them reaches the Function. Use Query to group invocations by route and client user agent to identify chatty callers, then remove or consolidate only the calls the application does not need. Use platform redirects to handle URL changes at the CDN layer, avoiding a Function invocation.

Copy link to headingFunction-proxied uploads

Large client payloads that traverse a Function only to reach storage add unnecessary execution. Vercel Blob client uploads use a token exchange and an onUploadCompleted callback, so the browser sends the payload directly to storage. This removes the payload from the Function path. The token and callback steps remain part of the workflow.

Copy link to heading5. Investigate with an agent

If you want an agent to investigate, start with read-only access and require route-level evidence before approving changes. Provide the team scope, project name, production environment, the specific window where invocations increased, and any recent framework upgrades or deployment changes. Have the agent tie each finding to one of the causes above and propose the matching fix from that section.

Copy link to headingAgent prompt

To get started with your coding agent, copy and adapt this prompt:

Investigate why Function Invocations increased for <project> in <team> during <window>.
Start read-only. First, inspect the metrics schema for that team scope — it is the
source of truth for available metrics:
vercel metrics schema --scope <team> --format json
Where available, query Function Invocations by route over the same team, project,
environment, and window:
vercel metrics <invocation-metric-id> --scope <team> --project <project> --prod --since <start> --until <end> --aggregation sum --group-by route --order-by value --limit 50 --format json
If grouped results truncate a route you care about, re-run with a --filter on that
route. If Function metrics are unavailable (they require Observability Plus), use
the dashboard's Vercel Functions view instead and say so in your findings.
Corroborate with deployment metadata and runtime logs:
vercel list <project> --scope <team> --environment production --status READY
vercel inspect <deployment-id-or-url> --scope <team>
vercel logs --scope <team> --project <project> --environment production --since <start> --until <end> --no-branch --json
Identify whether the increase is driven by unexpected dynamic rendering, prefetch
traffic, automated bots, or chatty clients. Inspect Route Handlers, Server Actions,
and layouts for dynamic API usage. Group results by cache result where available and
distinguish CDN HITs from background revalidations — treat only a plain HIT as a
result that did not invoke a Function. Return route evidence and a baseline before
recommending changes. Do not edit, deploy, change settings, purge caches, or mutate
data without my explicit approval.

Copy link to headingVercel Plugin

The Vercel Plugin turns your AI coding agent (e.g., OpenAI Codex, Claude Code, or Cursor) into a Vercel expert. It adds skills, slash commands, and current knowledge of Vercel tools. The plugin is optional; it isn’t required to follow this guide.

npx plugins add vercel/vercel-plugin

Copy link to heading6. Verify the fix

After deploying your changes, compare the same route and selected time range in Vercel Functions observability before and after the change.

Check the following indicators:

  • Total Function invocations for the route
  • Cache result distribution, where a response-cache change should show the intended traffic producing plain HIT responses
  • Error rate
  • Traffic sources by user agent, if you changed prefetch or bot handling

Do not treat a lower total as proof by itself. Traffic may have dropped, or the route mix may have changed. A strong fix should reduce invocations for the affected route across comparable windows, such as the same weekday and traffic period, without increasing errors.