Serverless functions and bandwidth are the two biggest cost drivers on Vercel, and often the most opaque.

Let’s see it in action. Imagine a fairly standard Next.js app with a few API routes and a lot of user-uploaded images.

// vercel.json (example)
{
  "version": 2,
  "builds": [
    {
      "src": "pages/api/**/*.js",
      "use": "@vercel/node"
    },
    {
      "src": "public/**/*.+(png|jpg|jpeg|gif|svg|webp)",
      "use": "@vercel/static"
    }
  ],
  "routes": [
    { "src": "/api/(.*)", "dest": "/api/$1" },
    { "src": "/(.*)", "dest": "/$1" }
  ]
}

Here, pages/api/**/*.js tells Vercel to bundle these files into serverless functions. Each function invocation incurs a cost based on execution duration and memory. The public/**/*.+(png|jpg|jpeg|gif|svg|webp) pattern indicates static assets served directly, which primarily incur bandwidth costs.

The Serverless Function Cost Maze

Vercel serverless functions are billed based on invocations, execution duration, and memory allocation.

  • Invocations: Every time an API route is hit, that’s an invocation. A high-traffic API endpoint can quickly rack up invocations.
  • Execution Duration: Longer-running functions cost more. If your API route takes 500ms to complete, it costs more than one that takes 50ms.
  • Memory Allocation: You configure memory for your functions. More memory means higher cost per GB-hour, but can sometimes lead to faster execution, a trade-off to manage.

Key Takeaway: Unnecessary computations within your serverless functions, or inefficiently written code, directly translate to higher bills.

Bandwidth: The Silent Killer

Bandwidth is the amount of data transferred from Vercel’s servers to your users. This includes HTML pages, CSS, JavaScript, images, and any other assets.

  • Large Assets: Serving large image files, unoptimized videos, or bloated JavaScript bundles will dramatically increase bandwidth consumption.
  • High Traffic: More users means more data served.

Key Takeaway: Content Delivery Network (CDN) caching is your friend here. If Vercel can serve an asset from its edge cache, it’s often cheaper and much faster than re-fetching it from your origin.

Optimization Strategies

1. Serverless Function Optimization

  • Reduce Payload Size:

    • Diagnosis: Use Vercel’s analytics or log aggregation tools (like Datadog, Sentry) to identify API routes with high invocation counts and/or long execution times. Look at the specific payloads being sent and received.
    • Fix: Implement payload validation and truncation. For example, if an API returns a large user object but the frontend only needs the name and email, only send those fields.
      // Example: Truncating API response
      export default async function handler(req, res) {
        const user = await getUserFromDB(req.query.userId);
        // Instead of returning the whole user object:
        // res.json(user);
        // Return only necessary fields:
        res.json({
          name: user.name,
          email: user.email,
        });
      }
      
    • Why it works: Smaller request/response bodies mean less data processed by the function and less data transferred over the network, reducing both execution time and potential bandwidth costs.
  • Efficient Data Fetching:

    • Diagnosis: Profile your serverless functions to see where time is spent. Look for repeated or N+1 database queries.
    • Fix: Use techniques like Promise.all to fetch data concurrently, and implement data loaders or caching within your function to avoid redundant database calls for the same data within a single invocation.
      // Example: Concurrent data fetching
      export default async function handler(req, res) {
        const [userData, postsData] = await Promise.all([
          fetchUser(req.query.userId),
          fetchUserPosts(req.query.userId),
        ]);
        res.json({ user: userData, posts: postsData });
      }
      
    • Why it works: Parallelizing I/O operations reduces the total execution time of the function, directly cutting down on duration-based costs.
  • Choose the Right Memory:

    • Diagnosis: Monitor function performance. If a function is consistently timing out or running slowly, it might need more memory. Conversely, if a function uses very little memory, you might be overpaying.
    • Fix: Adjust the memory allocation in your vercel.json or via the Vercel dashboard. For example, if a function is memory-bound, increase it from 128MB to 256MB.
      // vercel.json snippet for a specific function
      {
        "functions": {
          "pages/api/heavy-task.js": {
            "memory": 256
          }
        }
      }
      
    • Why it works: A properly sized function runs faster and more reliably, balancing the increased cost per GB-hour against reduced execution duration and fewer retries.
  • Disable Unused Features:

    • Diagnosis: Review your API routes. Are there any that are rarely or never called?
    • Fix: Remove or disable unused API routes. If a route is only needed for an infrequent administrative task, consider running it manually or as a one-off script instead of exposing it as a constantly available serverless function.
    • Why it works: Eliminating invocations for routes that aren’t used directly reduces costs to zero for those functions.
  • Leverage Edge Functions:

    • Diagnosis: Identify API routes that perform simple, stateless operations like A/B testing, redirects, or basic authentication checks.
    • Fix: Migrate these to Vercel’s Edge Functions, which run closer to the user and have a different pricing model (per request, with a generous free tier).
      // pages/api/edge-test.js (as an Edge Function)
      export default function handler(req, res) {
        // Simple check: return a header
        res.setHeader('X-Edge-Test', 'true');
        res.status(200).send('Edge Function');
      }
      
    • Why it works: Edge Functions are designed for low-latency, high-volume, simple tasks. They are often more cost-effective for these use cases than traditional Node.js serverless functions, as they avoid the cold start overhead and have a more granular billing structure.

2. Bandwidth Optimization

  • Image Optimization:

    • Diagnosis: Use Vercel’s built-in Image Optimization (next/image) or a third-party service. Analyze your site’s largest assets using browser developer tools (Network tab).
    • Fix: Implement next/image for all images. It automatically optimizes images for different screen sizes and formats (like WebP), and serves them from Vercel’s global CDN.
      // Example with next/image
      import Image from 'next/image';
      
      function MyComponent() {
        return (
          <Image
            src="/images/hero.jpg"
            alt="Hero Image"
            width={1920}
            height={1080}
            quality={75} // Adjust quality for balance
          />
        );
      }
      
    • Why it works: Vercel’s Image Optimization significantly reduces file sizes by serving appropriately sized and compressed images, directly cutting down on bandwidth consumption.
  • Code Splitting and Tree Shaking:

    • Diagnosis: Check your JavaScript bundle sizes using tools like webpack-bundle-analyzer (often integrated with Next.js). Large, monolithic JS bundles are a major bandwidth drain.
    • Fix: Ensure dynamic imports (import()) are used for non-critical code, and that your build process effectively removes unused code (tree shaking). Next.js does this automatically for pages and dynamic imports, but review custom component imports.
    • Why it works: Delivering only the necessary JavaScript to the user reduces the initial download size, saving bandwidth and improving load times.
  • Caching Strategies:

    • Diagnosis: Observe how often assets are re-downloaded by users or during testing.
    • Fix: Configure appropriate Cache-Control headers for your static assets. Vercel’s CDN respects these headers. For dynamic API responses that don’t change frequently, consider client-side caching or using Vercel’s ISR (Incremental Static Regeneration) or stale-while-revalidate patterns where applicable.
      // vercel.json for cache control on static assets
      {
        "headers": [
          {
            "source": "/(.*)\\.(js|css|png|jpg|jpeg|gif|svg|webp)",
            "headers": [
              {
                "key": "Cache-Control",
                "value": "public, max-age=31536000, immutable"
              }
            ]
          }
        ]
      }
      
    • Why it works: By telling browsers and CDNs how long they can cache assets, you reduce the number of requests that actually need to hit Vercel’s origin servers, thereby saving bandwidth.
  • Gzip/Brotli Compression:

    • Diagnosis: This is usually handled automatically by Vercel, but it’s worth knowing. Check if your server is configured to send compressed assets.
    • Fix: Vercel automatically applies Brotli and Gzip compression to text-based assets (HTML, CSS, JS). Ensure you are not manually decompressing and re-compressing data within your functions if Vercel is already doing it at the edge.
    • Why it works: Compression significantly reduces the size of data transferred over the network, saving bandwidth.

The next potential cost surprise after optimizing serverless and bandwidth will likely be related to database usage or third-party service integrations.

Want structured learning?

Take the full Vercel course →