スケールしてもお財布に優しいVercelのコストコントロール
はじめに
Vercelは、その優れた開発者体験と簡単なデプロイ機能により、多くの開発者に支持されています✨特に最近のAI文脈でも、v0やMCPサーバーのホスティング先としても注目を集めており、その利用範囲はますます広がっています!
しかし、サービスがスケールするにつれて、コストがボトルネックになるケースも少なくありません。「気がついたら予想外の請求が来ていた😇」という経験をした方もいるのではないでしょうか。Vercelの料金体系は、従量課金が基本となるため、特にトラフィックや処理量が増加すると、コストコントロールが重要になります。
この記事では、Vercelのコストに焦点を当て、効率的なコスト管理の方法について解説します!Vercelの機能を網羅的に解説するのではなく、あくまでコスト観点を中心に、具体的な最適化手法について詳しく説明していきます!
※ この記事は【LayerX/ベースマキナ/令和トラベル】サービスの成長に合わせたフロントエンドの進化で共有した内容を記事にしたものです。
Vercelの料金体系を理解する 📝
Vercelの料金体系は、その柔軟性とスケーラビリティを特徴としていますが、適切に理解しないと予期せぬコストが発生する可能性があります🤑ここでは簡単にVercelの料金体系を解説します!
プランの種類と基本料金(2025/03時点)
Vercelは、主に以下の3つのプランを提供しています
Hobbyプラン
個人開発者や小規模なプロジェクト向けの無料プランです。
基本的な機能を利用できますが、商用利用は制限されます。
他にも制限がありますが$0で始めることができます
Proプラン
中小規模のチームや商用プロジェクト向けのプランです。
個人開発でも商用利用を考える場合はこちらのプランに該当します。
$20から始まり、超過分は従量課金制になっています
Enterpriseプラン
大規模な企業やエンタープライズ向けのカスタムプランです。
高度なセキュリティ、パフォーマンス、サポートが提供されます。
料金は個別見積もりとなります。
公式における料金プランページでは、ProプランがPopularだとされており、本記事においても特にProプランにターゲットを絞って、最適化を考えます🤔💭
(Enterpriseを選択できる環境ではお金の心配は少ないかもしれないですしね!)
固定価格のオプション
コストに影響を与える要因として固定価格のオプションと従量課金があります。
固定価格のオプションは上記のプラン選択もその一つといえます
そして次に考えないといけないオプションはシートの数になります🧑🤝🧑
ダッシュボードにアクセスできる人数になるので、多くの場合は開発メンバーの数とイコールになると思います。
あとは並列ビルド数であったり、分析のためのObservability PlusやWeb Analytics Plusなどがありますが、必須のものではないためここでの説明は省略します!
※ Enterpriseプランにおいてはほとんどのオプションがデフォルトで含まれています
従量課金となる主な項目
従量課金となる主な項目は、プロジェクトの規模や利用状況によって変動し、コストに大きく影響を与える可能性があります😬なんなら固定価格のオプションは導入時に見積もりが立っているため、それ以上増えることがないですが、従量課金の項目は変動量が予測でしかないため、予期せぬコスト増加になるのはだいたいこちらが原因になってきます。日々チェックしておくべき従量課金の主な項目を挙げておきます
Function Duration (サーバーレス関数の実行時間)
Vercelのサーバーレス関数が実行された合計時間に基づいて課金されます
関数の複雑さや処理量が増加すると、実行時間も増加し、コストに影響します
Edge Requests (エッジリクエスト数)
Vercelのエッジネットワークから処理されるリクエスト数に基づいて課金されます
エッジ関数を使用する場合や、エッジネットワークからのデータ配信が多い場合に増加します
Fast Data Transfer (データ転送量)
Vercelのネットワークからインターネットへのデータ転送量に基づいて課金されます
APIレスポンスやアセット配信など、外部へのデータ送信が多い場合に増加します
Fast Origin Transfer (オリジンからの転送量)
Vercelのオリジンサーバーからエッジネットワークへのデータ転送量に基づいて課金されます
オリジンサーバーからエッジネットワークへのデータ送信が多い場合に増加します
ISR Writes (ISR書き込み)
Incremental Static Regeneration(ISR)による静的ファイルの再生成回数に基づいて課金されます
動的なコンテンツを頻繁に更新する場合に増加します
コストの監視と分析 💹
最適化に向けて、まずは何にどれくらい使われているのか確認しておく必要があります!
ビジネスドメインの特性による設計や構造の違いで、コスト面での課題となってくる項目もプロジェクトによって異なります👀
すでにVercelを利用している場合はダッシュボードの「Usage」より任意の期間の使用量を確認できます!当月の期間に関しては使用料に対する料金もここで確認できます!
これまでの料金はここでは確認できないので、「Invoices」より月毎、項目ごとの料金を確認するようにしましょう!
これら二つの場所で確認しておきたいのは、他の項目と比べて料金が高い項目と、料金の増加量が大きい項目です!
前者は今一番コストがかかっているところで、少しの改善で大きなコスト削減が見込める可能性がある項目になり、後者は今は問題になっていないけど、今後課題になってくる可能性がある項目になります。
特に増えている項目については気づいた時には冷や汗をかくことになってしまうこともあるので、月々のコストはメモしておきながらグラフなどで可視化しておくと早期に気づくことができます(ここはVercelさんもグラフ化してくれていないので機能要望出しておきます✉️)
また各項目で使いすぎている場合に、メールとWebで通知設定を設けることもできるので、サービスの特性に合わせて閾値を設定して、バースト検知できるようにしておきましょう!
また、Observabilityという機能がGAとなってこちらで各項目ごとの使用量が確認できるようになっています。Observability Plusを有効化しなければ過去3日間しか遡れないようになっていますが、ボトルネックとなっている箇所の特定や、最適化施策を導入した後の経過観察は可能なので活用しない手はないかと思います💪
コスト削減のための実践的なアプローチ 🌟
コスト削減のための具体的なアプローチを紹介しつつ、おすすめ度合いで⭐をつけています。
簡単に導入できるものや場合によっては検討しても良いものもあるので参考にしてみてください!
実行環境の最適化
MiddlewareによるBasic認証 ⭐⭐
VercelはBuildした環境に対する認証としていくつかの仕組みを持ち合わせています(Deployment Protectionと呼ばれています)。
Vercel AuthenticationはVercelにログインできるチームメンバーのみがアクセスできるような仕組みです。この機能自体は無料で有効にすることができますが、メンバーが増えると先に説明したシートの数が増えるため、開発メンバー以外にも社内のQAチームだったり、他のメンバーがBuildした環境を確認したい場合はシートの数だけ料金が増えてしまうことになります🥺
他にはShareable LinksといってBuildごとにURLが発行されて、URLを知っている人であればアクセスできる機能もありますが、環境ごとにURLを共有する手間が発生してしまいます。
また$150の追加課金を行えば、パスワード認証機能(Password Protection)を導入することもできます。
しかし追加課金なしに認証をかけられる方法があるのでこちらでご紹介します。
それはMiddlewareにてBasic認証を実装する方法になります。
import { NextRequest, NextResponse } from 'next/server'
export const config = {
matcher: ['/', '/index'],
}
export default function middleware(req: NextRequest) {
const basicAuth = req.headers.get('authorization')
const url = req.nextUrl
if (basicAuth) {
const authValue = basicAuth.split(' ')[1]
const [user, pwd] = atob(authValue).split(':')
if (user === '4dmin' && pwd === 'testpwd123') {
return NextResponse.next()
}
}
url.pathname = '/api/auth'
return NextResponse.rewrite(url)
}
Basic認証のuser名とパスワードを共有しておけば、どのBuild環境にもアクセスできるようになります💪
Middleware実行の削減 ⭐⭐⭐
ページの表示前に処理を挟むことができることで認証やフラグの設定、リダイレクトからパスの書き換え前まで行える便利なMiddlewareですが、適切な管理がされていないと無駄なコストが膨らんでいるかもしれません🫠
Middlewareへの課金は実行回数によって換算されるため、特別な処理が必要のない静的アセットなどをMiddlewareの対象から除外することでコストを削減することができます!
除外対象の設定はMatcherより正規表現によって指定することができます。
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico, sitemap.xml, robots.txt (metadata files)
*/
'/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)',
],
}
静的アセットやSEO向けのメタデータファイルなどは除外しておくとコストを抑えることができ、加えてコスト観点以外にもMiddlewareでの認証を導入している場合に、認証をバイパスしたいファイルなども例外ルールとして扱うことができるので頭の片隅に置いておくと良さそうです🥳(例としてユニバーサルリンクやアプリリンクの導入ケースにおいて、Staging環境で/.well-known
配下は認証をバイパスしたい場合など)
💬 2025年2月よりNext.js 15.2からNode.jsがサポートされました
Fluid Computeの有効化 ⭐⭐⭐
2025年2月に新しいサーバーレスの形として、Fluid Computeというモデルを発表しました。これはリクエストに応じて関数を起動するサーバーレスの形はそのままに、1リクエスト=1関数インスタンスではなく、1リクエストで複数の関数呼び出しを処理するミニサーバーという立て付けになっているようです。これによってコールドスタートの削減やリソースの有効活用によってコストが最適化されるようになっています。
関数内での並列処理の機能はFluid ComputeまではIn-function concurrencyとして提供されており、これを有効化している場合は自動的にFluid Computeも有効化されているのですが、まだFluid Computeが有効になっていない場合は、有効化してみるとコストの減少が期待できるかもしれません。
注意点として有効化した場合に関数のタイムアウトまでの時間(Max duration)のデフォルト値が変更になります。何もカスタマイズしていない場合は、Proプランの場合15秒から90秒に変更されているので、今までタイムアウトが多く発生していた場合などはコストが増加する可能性もあるので気をつける必要があります!
ビルドとデプロイの最適化
Github Actionsによるシートの節約 ⭐
VercelのGithub連携を行っておくとPR作成時に自動でPreview環境を作成してくれたりしますが、Vercel上に権限がないメンバーがPRの作成者だった場合はBuildが失敗するようになっています。そのためチームの全員にVercelの権限を与える必要が発生しますが、一人当たり$20必要になるのでチームが増えてくるとそれだけでコストが嵩んでしまいます🥲
そこでもし全てのメンバーがダッシュボードにアクセスする必要がない場合は、Github Actions経由でVercelにデプロイするとシートの節約が可能です!ただし主導によるデプロイなどもできないため、チーム構成や運用方法としてマッチする場合のみ検討すると良さそうです!
モノレポ環境で不要なBuildはスキップ ⭐⭐⭐
モノレポ環境でPR毎にPreview環境を構築している場合は、無駄なBuildが発生しているかもしれません!Turborepoを利用している場合、Skip deploymentsを有効化しておくことで変更差分のないプロジェクトのBuildがスキップされるようになります!
この機能は2024年7月より誕生しましたが、2025年2月よりデフォルトで有効化されるようになっているため、まだ有効化していない場合は一度見直してみると無駄が削減されるかもしれません!
また同じような機能としてIgnored Build Stepというものがあります。これは特定のブランチやディレクトリに変更があった場合のみBuildを走らせることができるという機能になります。より詳細な条件設定ができる点と、Buildが走った後に無効化されるという点において違いがあるみたいです。
💬 モノレポ内の同一プロジェクトに同一ドメインでリバプロする時の料金は2重課金?!
モノレポ内の同一プロジェクトに同一ドメインでリバプロする時は複数回のリクエストとして課金されるでしょうか?
例えばNEWTの場合だとツアーとホテルは別プロジェクトとして開発しています。その中でnewt.netはツアーを、newt.net/hotelはホテルを表示するとき、ツアー側でリバプロ(Next.jsでいうrewrite)を通してホテルへアクセスするようになっています。この場合ツアーへのアクセスもホテルのアクセスも課金されているでしょうか?
元々はどちらも課金される形でしたが、2025年2月より最適化が行われ、単一のアクセスとして扱われるようになりました。これで安心してプロジェクトを分割して管理できるようになります🥰
レンダリングとデータ取得の最適化
レンダリングの最適化 ⭐⭐
レンダリング方法において、頻繁に更新されるコンテンツを配信していない場合は、SSGを検討されるかと思います。次点でSSRとのいいとこ取りをしたい場合にISRが選択肢となってきますが、ISRを選択するときは時間によって更新が行われるTimebased Revalidateよりも、コンテンツ更新をトリガーに行うOn-demand Revalidationを採用できないか検討しましょう!
2025年2月にISRのコスト最適化がVercelで行われたものの、ISR Writeでは8 KBごとを1単位として課金されていく体系は変わっていません。
何よりOn-demand Revalidateにすることによって不要な関数実行が減少することで、Function Durationの削減が期待できます。
プレフェッチを無効化 ⭐⭐
next/linkのLinkのprefetchは、デフォルトで有効化されており、これによってパフォーマンスが向上するのに対してコストは大きく増えている可能性があります。グローバルで無効化する設定が存在しないため、個別のリンクに対して遷移先ページが重要でないページや、パフォーマンスが求められないページにおいては無効化することを検討しましょう!
認知しておくべき点としては無効化した時の挙動がPages RouterとApp Routerで異なる点です。
App Routerではビューポートに入った時と、ホバーした時の両方において無効化されます。Pages Routerにおいては、ビューポートに入った時の挙動は無効化されているのに対してホバー時は無効化されません😳
パフォーマンスとリソースの最適化
画像最適化 ⭐⭐
2025年2月に新しい画像最適化の価格モデルが発表されました🎉
これまでnext/imageによる画像最適化は、最適化された画像数により追加で料金が発生しましたが、新しい画像最適化の価格モデルと有効化すると、最適化に基づく使用量で課金されることになりました。
next/imageに関してはこちらも参考に🙋♂️
ただし、画像最適化されていたとしても静的アセットとしてセルフホストされている場合は、最適化に対する料金とプラスしてFast Data Transferの料金としても加算されてしまいます。
そこで画像のホスティングはサードパーティのCDNs (Content Delivery Networks)に任せてしまうと、プラットフォームによってはCDNの料金とプラスしても安上がりになることがあります。
弊社では画像CDNとしてImgixを利用しており、パラメータによって画像最適化も行われるため、全ての画像に対してnext/imageを使わないようにしています!
Bundle Sizeの見直し ⭐
おそらく従量課金の中で最もコストがかかってくるものの一つがFast Data Transferになると思います。Fast Data Transferの最適化方法として挙げられているのが、先に挙げた画像の最適化とバンドルサイズの最適化になります。
バンドルサイズの最適化にはまず分析を行い、ボトルネックとなる箇所を特定する必要があります。
分析には@next/bundle-analyzerが利用できます。実際にNEWTをbundle-analyzerによって分析した画像がこちらになります
これによって大きなサイズを占めているモジュールは何かを特定できそうです。この画像からはlibphonenumber.jsがかなり大きな割合を占めていることがわかります。
ボトルネックとなっているモジュールを見つけたら次は最適化できないかを考えます。アプローチとしては
- 使用されていないモジュールやライブラリの場合は削除する
- より軽量な代替となるライブラリに置き換える
- コード分割を検討する
- Dynamicインポートにより必要な場面でのみ読み込みを行う
あたりが考えられ、今回の場合だと代替となるライブラリで良さそうなものがなかったため、Dynamicインポートによって対応しました。それによって500kb近くのバンドルサイズの削減がおこなれ、コストも大きく削減することができました。
💬 バンドルサイズの観点からGraphQL Client-Presetを見送った話
弊社ではデータ取得にアプリもWebもGraphQLを利用しています。Schemaからのコード生成をCodegenを用いて行なっており、CodegenとしてはClient-presetを推奨しているため、移行を進めていました。進めている中で生成されるコードがバンドルサイズを押し上げることがわかり、コード分割またはツリーシェイキングを行う必要が発生しましたが、そのための公式プラグインの開発が止まっていることからCliet-presetへの移行を中断しました。
バンドルサイズの調査なしに移行を進めてしまった場合、Fast Data Transferを一気に上げてしまう可能性があったためライブラリの変更や、大きな実装の変更時はチェックしておくと良さそうです
監視とログ管理の最適化
Log Drain ⭐
Vercelでデプロイしたアプリのランタイムのログを確認したい時、ダッシュボードのLogsタグから確認することができます。ログレベルから、Functionの種類、ホストやリクエストメソッド、リクエストパスなどで絞り込むことができ、リッチなUIで確認することができる一方で、Proプランだと過去1日分しか確認できません😭
インシデントが発生した時などは過去のログを遡って確認したいことは往々にしてあるので、これでは困ります!
ログを長期間永続的に保存して確認できるようにするためにLog Drain機能を利用します。
弊社ではログの保存先としてGoogle CloudのCloud Loggingを利用しています。APIサーバーもGoogle Cloudを活用しているため、APIログと同じインターフェースで確認することができます。ログの送信にはCloud Loggingのフォーマットに合わせて整形する必要があるためCloud Run functionsを経由しています。
元々Log Drainは無料の機能として提供されていたのですが、GAのタイミング(2024年5月)で従量課金制となり、その後値下げが入り(2024年8月)、現在は20GBごとに$10になっています。全てのログを送るとここで料金が高くなってしまうので、Build時のログのみや、Edgeでのログのみなど必要に応じて送信するログのソースを限定しておきましょう!
まとめ
サービスの成長にコストがボトルネックにならないように、日々コストコントロールを意識しましょう!

令和トラベルのTech Blogです。 「あたらしい旅行を、デザインする。」をミッションに、海外旅行におけるあたらしい体験や、あたらしい社会価値の提供を目指すデジタルトラベルエージェンシーです。海外ツアー・ホテル予約アプリ「NEWT(ニュート)」を提供しています。(NEWT:newt.net/)
Discussion