DEV Community

Cover image for Optimizing Vercel Hosting Costs
Kinga Kwapisz for Pagepro

Posted on • Originally published at pagepro.co

Optimizing Vercel Hosting Costs

Introduction

Using Vercel is a popular choice for hosting apps, thanks to its ease of use and support for Next.js framework. This hosting platform can accommodate even large traffic spikes and different use cases. However, as your projects scale their hosting costs can grow as well and have you look elsewhere for a different hosting provider.

Still, there’s a way to limit how much you’re spending on cloud hosting and make Vercel support the budget of your Next.js app. Even small adjustments to the code, how you configure your project settings, deploy your project, or how often check the dashboard can make a difference.

In this step-by-step guide I’ll introduce you to smart strategies we’re using to lower hosting expenses, and help you decide when staying on a Pro subscription is the best choice, and when upgrading to Enterprise is necessary.

Chris Lojniewski and I held a live session on this subject, which included a live demo of the optimizations I’ll be describing in the article. You can watch it here.

Now, let’s start by breaking down what affects your Vercel hosting bill

Factors Driving Costs in Vercel

We can divide the factors influencing your costs into Fixed-Price and Usage-Based

Fixed-Price Factors

These stay roughly the same each month, as Vercel sets their price for all users.

  • Plan Selection – When starting a new project, choosing the right plan matters, especially if you’re too big for the generous free tier Vercel offers. Before you start the deployment process, ensure your plan aligns with your expected usage so your project can be deployed quickly and securely. Hobby, Pro, and Enterprise plans have different pricing structures and limits. The Pro plan includes additional resources but charges for overages, while the Enterprise plan offers custom pricing based on usage.

  • Number of Seats – Vercel charges per seat for users needing access to the dashboard. Make sure that only necessary team members have access to your repository or use automation (e.g., GitLab CI/CD or GitHub Actions for deployment, which I’ll talk about more later).

Usage-Based Factors

This type of costs can rise or fall, depending on your setup and decisions.

  • Execution Time – You’re billed based on the total time serverless functions take to execute. Vercel’s automatic scaling helps optimize performance by adjusting resources based on traffic demand.

  • Invocations – Each time a serverless function runs, it becomes an invocation. High invocation counts can quickly increase costs, particularly if middleware, API routes, or unnecessary prefetching is triggering multiple function calls. You can avoid this by limiting function calls and caching responses where possible.

  • Bandwidth – The volume of JavaScript bundles, images, API responses, and any external asset loads transferred between users and the server contributes to costs. Compressing assets, reducing data payloads, and utilizing caching strategies can reduce bandwidth expenses.

Vercel Hosting Cost Factors

Once you become aware of what affects your bill, you can start working on lowering it. To help you, I’ve prepared a list of the code optimizations we’ve been using in our projects, which you can implement as well.

Lowering Hosting Costs with Code Tweaks

Sometimes smart and strategic choices and taking advantage of Vercel as the easiest way to deploy Next.js applications without breaking the bank. Below are the examples of code-level adjustments we’ve been using in our projects to lower the costs.

Choosing the Optimal Rendering Method

Rendering methods play a significant role in shaping your hosting costs. Using Static Site Generation (SSG) is an effective way to minimize execution costs and reduce unnecessary deploying. It lets you shift processing from runtime to build time, a particularly useful feature for content that does not change frequently. 

Server-Side Rendering (SSR) on the other hand, should be used sparingly, as it adds new execution costs with every page request. Incremental Static Regeneration (ISR) balances the two by allowing updates to static content at scheduled intervals. This reduces unnecessary function executions while keeping content fresh.

Minimizing Data Transfer

Large API payloads can lead to increased bandwidth usage and higher costs. Efficient query techniques, such as database-level aggregations instead of frontend filtering, can significantly cut down on data transfer

getStaticProps applied for pre-building pages rather than fetching data at runtime stops users from repeatedly triggering API requests.  This further reduces bandwidth consumption, but limiting the props passed to pages can also decrease data transfer volumes and improve page load times.

Optimizing Prefetching

Knowing how to optimize prefetching is crucial in controlling function invocations. Next.js prefetches links by default, which can lead to excessive function executions when multiple pages are loaded in advance. While this improves performance, it can also increase costs unnecessarily, a common problem in the modern web development process. 

Disable prefetching for non-critical pages or implement hover-based prefetching to balance top performance and cost efficiency. 

Function Optimization

Function execution time directly impacts hosting expenses. Optimizing its performance is key to savings. Instead of making multiple sequential API requests, parallelize requests using Promise.all() to reduce execution time. 

Database queries should also be optimized to minimize expensive calculations within API functions. Offload long-running processes like PDF generation to background jobs outside Vercel and implement caching strategies to limit unnecessary API requests, so frequently accessed data is served efficiently.

Reducing Middleware Executions

Badly managed middleware executions can accumulate unnecessary costs. Implementing route matchers makes middleware run only when required, lowering strain on the back-end and preventing excess function executions. Static assets should be excluded from middleware processing to optimize performance and reduce costs. 

Regex filters can further refine when middleware is executed, allowing developers to fine-tune application behavior without incurring excessive execution charges. Here’s how you can do it:

export default async function middleware(request: NextRequest) {
 if (!request.nextUrl.pathname.startsWith("/protected")) {
   return NextResponse.next();
 }


 // OTHER MIDDLEWARE ACTIONS


 return NextResponse.next();
}


export const config = {
 matcher: [
   "/((?!api|_next/static|_next/image|favicon.ico|assets|.*\\.png$).*)",
 ],
};
Enter fullscreen mode Exit fullscreen mode

Optimizing Vercel Dashboard

Vercel Dashboard
Vercel Dashboard View

A lot of the savings for your app can be found in the Vercel dashboard settings, depending on how you want to deploy it.

  • Setting maximum execution time for functions helps prevent excessive processing costs. This ensures that long-running functions do not consume unnecessary resources, avoiding unpredictable costs caused by inefficient execution loops.

  • The Fluid Compute feature is another valuable addition Vercel offers. It allocates resources to functions, which helps balance cost and performance by optimizing resource utilization based on demand. Enable it in your app to test the potential gains it might offer.

  • New image optimization pricing has changed Vercel’s billing approach. Instead of charging based on the number of images transformed, costs are now tied to transformation actions. However, the platform still supports a variety of optimization strategies. Teams should review their image processing workflows and limit unnecessary transformations.

  • Performing front-end bundle analysis using tools like Lighthouse and Webpack Analyzer helps identify and eliminate unused JavaScript and CSS, reducing page load times and bandwidth consumption. Streamlining bundles ensures assets are delivered without adding to hosting costs. Taking advantage of features of Next.js, such as automatic code splitting and tree-shaking, can help you further optimize performance.

  • Remember to allocate only the necessary resources for each function. You’ll be able to avoid over-provisioning, reduce execution time expenses, and properly set a custom domain without unnecessary redirects or misconfigurations. Regularly monitoring and fine-tuning these settings will help you match actual usage needs to avoid overpaying.

Alternatives to Vercel Premium Features

Lowering reliance on Vercel’s premium features like image optimization through alternatives can lower your costs while maintaining a high-performing app. 

  • Limiting seats using solutions like GitHub workflows is an effective strategy. Instead of granting all team members direct access to the Vercel dashboard, teams can configure GitHub Actions to automate Vercel’s deployment. This removes the need for additional paid seats but also restricts real-time monitoring, debugging, and direct deployment control.

  • Image optimization is another area where external solutions can help cut expenses on Vercel. The platform integrates seamlessly with third-party CDNs (Content Delivery Networks) and CMSs (Content Management Systems) which makes it easy to reduce reliance on Vercel’s image handling if you are already using one of these.

  • Built-in analytics tools can also be replaced with third-party solutions like DebugBear, SpeedCurve, or web.dev. 

  • For password protection, instead of using Vercel’s built-in feature, you can implement middleware-based authentication. Redirecting users to a custom authentication route lets developers control access without incurring extra Vercel costs.

How to Implement Password Protection with Middleware

To implement password protection outside of Vercel’s built-in tools, you’ll need to do three things. First is the setting of the middleware, which will check your password. Start by updating your middleware file with this code:

import { NextRequest, NextResponse } from "next/server";


function checkForPassword(request: NextRequest) {
 const hashedPassword = request.cookies.get("site-access")?.value;
 const envPassword = process.env.SITE_PASSWORD;


 if (!envPassword) {
   return null;
 }
 // You should use a better hashing algorithm here
 const hash = (str: string) => Buffer.from(str).toString("base64");


 if (!hashedPassword || hashedPassword !== hash(envPassword)) {
   const response = NextResponse.rewrite(
     new URL("/password-check", request.url)
   );
   response.cookies.set("requested-path", request.nextUrl.pathname);
   response.headers.set("cache-control", "no-store, must-revalidate");
   response.headers.set("x-middleware-cache", "no-cache");


   return response;
 }
}


export default async function middleware(request: NextRequest) {
 const redirectResponse = checkForPassword(request);


 if (redirectResponse) {
   return redirectResponse;
 }


 return NextResponse.next();
}


export const config = {
 matcher: [
   "/((?!api|_next/static|_next/image|favicon.ico|assets|.*\\.png$).*)",
 ],
};
Enter fullscreen mode Exit fullscreen mode

Now that this is ready, it’s time to set up the page which will prompt for a password. Create a file in the /app/password-check/page path and type this:

"use client";


import { useState } from "react";
import { useRouter } from "next/navigation";


export default function PasswordCheck() {
 const [password, setPassword] = useState("");
 const [error, setError] = useState("");
 const router = useRouter();


 async function handleSubmit(e: React.FormEvent) {
   e.preventDefault();


   try {
     const response = await fetch("/api/password", {
       method: "POST",
       body: JSON.stringify({ password }),
     });


     if (!response.ok) {
       throw new Error("Failed to validate password");
     }


     const requestedPath =
       document.cookie
         .split("; ")
         .find((row) => row.startsWith("requested-path"))
         ?.split("=")[1] || "/";


     router.push(requestedPath);
   } catch {
     setError("Invalid password. Please try again.");
   }
 }


 return (
   <main className="grid place-items-center min-h-[100vh] bg-gray-50 p-4">
     <div className="w-full max-w-sm space-y-4">
       <h1 className="text-3xl font-bold text-center text-gray-900">
         Access Forbidden
       </h1>
       <p className="text-sm text-center text-gray-600">
         This page is protected by password. To access the site, please ask the
         administrator for the password and type it below.
       </p>


       <form onSubmit={handleSubmit} className="space-y-4">
         <input
           type="password"
           value={password}
           onChange={(e) => setPassword(e.target.value)}
           className="w-full px-3 py-2 border rounded text-gray-900 placeholder-gray-500 focus:ring-2 focus:ring-indigo-500"
           placeholder="Enter password"
         />


         {error && <p className="text-red-500 text-sm text-center">{error}</p>}


         <button
           type="submit"
           className="w-full py-2 px-4 bg-indigo-600 text-white text-sm font-medium rounded hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500"
         >
           Submit
         </button>
       </form>
     </div>
   </main>
 );
}
Enter fullscreen mode Exit fullscreen mode

The last step is to create an API request for password verification since client logic doesn’t have access to environment variables. Create a new file in the /api/password/route path and type:

import { NextRequest, NextResponse } from "next/server";


export async function POST(request: NextRequest) {
 try {
   const { password } = await request.json();


   if (password !== process.env.SITE_PASSWORD) {
     return NextResponse.json(
       { message: "Invalid password" },
       { status: 401 }
     );
   }


   const response = NextResponse.json(
     { message: "Password valid" },
     { status: 200 }
   );


   // Set secure HTTP-only cookie with base64 encoded password
   response.cookies.set({
     name: "site-access",
     value: Buffer.from(password).toString("base64"),
     httpOnly: true,
     sameSite: "strict",
     path: "/",
   });


   return response;
 } catch {
   return NextResponse.json(
     { message: "Error validating password" },
     { status: 500 }
   );
 }
}
Enter fullscreen mode Exit fullscreen mode

Bear in mind, this is not the perfect solution for apps requiring high security. Companies that need to adhere to strict standards or handle sensitive information might be better off using Vercel’s built-in protections. Speaking of…

When Do You Need Vercel Enterprise?

Vercel Plans
Source: Vercel

Time to discuss the elephant in the room – is upgrading to Enterprise necessary for growth? The answer depends on what your project requires. 

Vercel Enterprise is designed for businesses that need security, scalability, dedicated support, and advanced features. While the Pro plan is enough for most applications, Enterprise offers additional features for high-traffic, compliance-driven, or mission-critical applications.

You’ll Need Enterprise If:

More Support is Necessary 

Enterprise customers receive dedicated customer support with service level agreements (SLAs) guaranteeing uptime and response times. This level of support could be a good investment if your app relies heavily on uptime and fast troubleshooting.

You’re Constantly Exceeding Pro Plan Limits

In case when a project exceeds Pro plan limits in execution time, bandwidth, or function invocations, Enterprise can provide a more flexible usage allowance with a custom pricing option. This can be the less expensive option compared to paying for overages on the Pro plan.

Security and Compliance Are a Must 

Compliance standards like SOC 2, ISO 27001, and HIPAA require strict data handling policies that Enterprise plans support. Single Sign-On (SSO), role-based access control, private networking, and dedicated infrastructure could be needed if your organization handles sensitive data.

Security Measures in Vercel Enterprise
Source: Vercel

Advanced Performance Optimization Options Can Help Your App 

Enterprise users have access to additional performance improvements. This includes enhanced CDN configurations, lower cold start times, and priority deployment processing for faster build times.

Custom Billing and Procurement is Important to You 

Larger companies often require flexible billing arrangements, invoicing options, and procurement workflows aligning with internal procedures. Vercel Enterprise allows for custom contracts, bulk seat management, and additional auditing capabilities.

Enterprise Won’t Be Necessary If:

You’re Running a Small to Mid-Sized Project

Vercel supports the hosting and deployment of a variety of apps, from personal projects outgrowing the Free plan, to e-commerce sites. All of them can run efficiently on the Pro plan without requiring the additional features of Enterprise.

The App You’re Working on Is Cost-Sensitive 

If budget control is your priority, explore cost optimizations within the Pro plan, like reducing function executions, optimizing data transfer, and limiting seats. It can be a better (and more affordable) solution than upgrading to Enterprise.

There Are Alternative Hosting Solutions You Can Pursue

In a situation where Vercel’s pricing becomes unsustainable at scale, you might consider alternative hosting solutions. Self-managed cloud infrastructure (AWS, GCP, Azure) or hybrid deployments that combine Vercel with other providers for cost efficiency can be a good investment.

Before deciding on upgrading, carefully evaluate your business requirements, traffic volume, and budget constraints. Only then you’ll know if Vercel Enterprise will provide you with a better value than sticking to Pro plan.

Conclusion

Vercel has evolved over the years to accommodate different Next.js apps in modern development. Keeping it affordable comes down to making smart choices. Simple tweaks to rendering, function execution, and dashboard settings can save your budget

It’s important to remember that your subscription matters. For most projects, the Pro plan is enough with the right optimizations, but if security, compliance, or heavy traffic are concerns, Enterprise might be the better, and sometimes even more affordable fit. As long as you understand your usage and align your hosting strategy with business goals, Vercel makes hosting cost-effective for your Next.js applications, whether you’re working on a small project, web application, or a big venture. 

Read More

Top comments (0)