3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js が Lambda でそのまま動く!Lambda Web Functions を Cloud Run と比べてみた

3
Posted at

はじめに

2026年10月12日、AWS Lambda に「Web Functions」が一般提供(GA)になりました。

Announcing AWS Lambda Web Functions

Next.js や Express のような普通の Web サーバーを、アダプターなしで Lambda に載せられる新しい関数です。

私は普段 Google Cloud をメインに開発をしていて、Web アプリや API は Cloud Run で動かすことが多いです。Cloud Run も HTTP リクエストを受けて動くサーバーレスのサービスなので、Lambda Web Functions とどのくらい違うのかが気になりました。
そこで同じ Next.js 16 のアプリを Lambda Web Functions と Cloud Run の両方にデプロイして違いを調べてみました。

Lambda Web Functions とは

今回のアップデートで Lambda は3種類になり、従来のイベント駆動の Lambda は「Event Functions」という名前に変わりました。今回そこに「Web Functions」と「Lambda MicroVMs」が加わっています。

Web Functions は、アプリがポートで待ち受けて、普通の Web サーバーとしてリクエストを受ける形になっていて、API Gateway や Lambda 用のアダプターは必要ありません。
公式では Express、Hono、Fastify、Next.js などがそのまま動くと案内されています。

What's New: AWS Lambda Web Functions

主な仕組みは次のとおりです。

  • 関数・リビジョン・エンドポイント:
    • リビジョンはコードと設定の変更できないスナップショットで、エンドポイントが HTTPS の URL
    • 1つのエンドポイントで、最大2つのリビジョンに重みを付けて振り分けられる
  • 実行環境:
    • Node.js 24、Arm64、2 vCPU / 2 GB で固定
    • 1つの環境が、既定で64件(最大128件)まで同時にリクエストを受信
  • スケール:
    • リクエストに応じて環境が増減し、ゼロまで縮みます。最小の環境数は設定不可
  • 認証:
    • エンドポイントごとに「なし(アプリ側で行う)」か「IAM(SigV4)」を選択
  • ネットワーク:
    • VPC の中のリソースには、egress network connector を通して繋ぐ
  • リージョン:
    • 東京(ap-northeast-1)を含む5リージョンで利用可能

Lambda Web Functions の全体像。クライアントからエンドポイント、重み付きでリビジョンへ振り分け、実行環境が 0 から増減し、egress network connector で VPC につなぐ

Cloud Run との違い

Cloud Run はコードやコンテナを Google Cloud のインフラ上で動かせるフルマネージドのサービスです。中でも「サービス」は HTTPS のエンドポイントを持ち、リクエストの数に応じて自動でスケールし、リクエストがなければインスタンスがゼロまで縮むので、Lambda Web Functions と同じ立ち位置になります。
(もちろんサービスのコンセプトから異なる部分はあります)

What is Cloud Run

以前の Cloud Functions も今は Cloud Run functions として Cloud Run に含まれているので、Google Cloud で Web アプリや API をサーバーレスで動かすなら、Cloud Run が比較の相手になると考えました。

今回は Cloud Run のサービスと比べていますが、主な違いは次のとおりです。

Lambda Web Functions Cloud Run
言語 Node.js 24 のみ コンテナなら何でも
サイズ Arm64、2 vCPU / 2 GB 固定 0.08〜8 vCPU、最大 32 GiB
コードの渡し方 .zip(S3)のみ コンテナイメージ、ソース
最小インスタンス 設定なし あり
WebSocket 不可 可
課金 使った CPU 時間+使ったメモリ × 環境がある時間 処理中の時間(または起動中ずっと)

Lambda 側は、2026年10月16日時点の開発者ガイドの内容をもとにしています。

表にしてみるとCloud Run と比べて選べる項目はかなり少ないことがわかります。
特に最小インスタンスが設定できない点と WebSocket が使えない点は、Cloud Run に慣れていると気になるところですね。

Next.js をデプロイする

Next.js は output: "standalone" でビルドし、起動用のファイルを1つ追加したら動きました。

Lambda は待ち受けるホストとポートを環境変数 AWS_LAMBDA_HTTP_ENDPOINT(host:port の形)で渡してきます。
一方で Next.js の standalone サーバーは HOSTNAME と PORT を読むので、起動前に値を詰め替えておく必要があります。

.next/standalone/index.js
// Lambda は既定で index.js を起動する
if (process.env.AWS_LAMBDA_HTTP_ENDPOINT) {
  const [host, port] = process.env.AWS_LAMBDA_HTTP_ENDPOINT.split(':');
  process.env.HOSTNAME = host;
  process.env.PORT = port;
}
require('./server.js');

準備: S3 バケットと実行ロール

コードは S3 経由で渡すため、バージョニングを有効にしたバケットを用意します。
実行ロールは lambda.amazonaws.com を信頼させ、権限は CloudWatch Logs への書き込みだけにしています。

aws s3api create-bucket --bucket <バケット名> --region ap-northeast-1 \
  --create-bucket-configuration LocationConstraint=ap-northeast-1
aws s3api put-bucket-versioning --bucket <バケット名> \
  --versioning-configuration Status=Enabled

aws iam create-role --role-name lwf-verify-exec-role \
  --assume-role-policy-document file://exec_role_trust_policy.json
aws iam put-role-policy --role-name lwf-verify-exec-role \
  --policy-name lwf-verify-logs --policy-document file://exec_role_permissions_policy.json

ビルドしてデプロイ

ビルドしたらstandalone の出力に静的ファイルと先ほどの index.js をまとめて、aws lambda-web deploy に渡します。

npm run build
cp -R .next/static .next/standalone/.next/static
cp -R public .next/standalone/public
# .next/standalone/index.js を置く(上のコード)
# Mac でビルドするなら Linux arm64 用の sharp も足す(npm install --os=linux --cpu=arm64 sharp)

aws lambda-web deploy --name lwf-verify-next --code ./.next/standalone \
  --bucket-name <バケット名> \
  --execution-role-arn arn:aws:iam::<アカウントID>:role/lwf-verify-exec-role \
  --create

実行して14秒ほどで、HTTPS の URL が返ってきました。

Waiting for revision rev-jj9hm to become active (timeout 600s) ...
https://xxxxxxxx.kfn.lambda-web.ap-northeast-1.on.aws

Lambda コンソールのウェブ関数。エンドポイント dev が Active、最新リビジョンに 100%

コンソールを開いて確認してみると、関数と最初のリビジョン、HTTPS のエンドポイント(dev)がまとめて作成されていることがわかります。
今回は認証なしのエンドポイントなので、この URL をそのままブラウザで開けます。

Next.js 16 の SSR ページ。arm64 / node v24.21.0 / cpus 2 と表示

今回は確認しやすいように、ページには実行環境の情報を表示させています。
arm64、Node.js v24、CPU 2つの環境で動いていることがわかります。

CloudWatch Logs のログストリーム。initStart、listening、リクエストのログが並ぶ

ログは CloudWatch Logs の /aws/lambda/web/<関数名> に出力されます。
起動(initStart)、listen、リクエストの順に並ぶため、コールドスタートだったかどうかもここで見分けられます。

Cloud Run 側は、同じコードを使って次のコマンドでデプロイしています。

gcloud run deploy lwf-verify-next --source ./next-app \
  --region asia-northeast1 --cpu 2 --memory 2Gi --no-invoker-iam-check

Cloud Run と比べてみた

デプロイにかかった時間は Lambda が14秒、Cloud Run が2分50秒でした。
Cloud Run はソースからコンテナをビルドする工程がある分、時間がかかっていますね。

Next.js でもコールドスタートは Lambda が半分以下。Lambda 平均 1.14 秒、Cloud Run 平均 2.54 秒

コールドスタートは20分放置して両方のインスタンスがゼロに戻ってから、最初の1件の応答時間を測ってみました。
4回とも新しい環境で起動していて、平均は Lambda が1.14秒、Cloud Run が2.54秒と、Lambda が半分以下という結果になりました。

負荷時のスケーリングについて

次にSSR のページに同時50件のリクエストを30秒流して応答速度やスケーリングの違いについて確認してみました。

p50 はどちらも約1.54秒ほどで応答の速さに差はありませんでしたが、裏側の動きはそれぞれでかなり違いがありました。
Lambda は環境を36個立ち上げていて、1つの環境が同時に処理していたのは最大でも2件となっていました。
一方で Cloud Run は、1台のインスタンスで全部を受けていました。

同時50件のとき、Lambda は36環境に分散、Cloud Run は1台(上限160件、96件で増える)

Cloud Run は、新しく作ったサービスだと1台が同時に受けられるリクエストの数が既定で「80 × vCPU 数」(今回は160件)となっているようで、CPU 使用率が6割、または同時に受けているリクエストが上限の6割を超えるとインスタンスを増やす仕組みのようです。

今回の50件は1台で十分に受けられる量だったため、インスタンスが増えなかったのだと思いますが、最大インスタンス数(既定100)はあくまで上限なので、ここを変えても結果は同じになると思います。

Lambda も1つの環境で同時に受けられるのは既定で64件なので、1つの環境にもっと詰め込めるはずですがLambda は環境を増やして分散させる動きをするようです。

この動きで影響が出るのが DB につなぐ場合で、同時100件のリクエストで Aurora への接続が 145本 になりました。

DB につなぐときは接続数に注意
Lambda は環境を増やして分散させるため、環境ごとに持つ接続プールがそのまま積み上がります。今回は同時100件で環境が72個まで増え、Aurora への接続は145本になりました。
本番で使うなら、RDS Proxy を挟むか、maxEnvironments で環境の数に上限をかけておきたいところですね。

Cloud Run でやっていることはできるか

普段 Cloud Run で動かしているような構成が、Lambda Web Functions でも組めるかを試しました。

やりたいこと 結果 メモ
AI エージェント(Bedrock の Claude Haiku 4.5) ○ 1件5.8秒のうち、CPU は0.2秒
VPC 越しの DB(Aurora Serverless v2) ○ 接続数に注意(上記)
IAM 認証 ○ IamAuth にすると署名なしは 403
カナリアリリース △ deploy は新リビジョンに100%切り替える。重みの反映に15〜30秒
コンテナイメージ × .zip のみ
WebSocket × Upgrade ヘッダーが消される

Cloud Run でやっていることはできるか。IAM 認証、AI エージェント、VPC 越しの DB は○、カナリアリリースは△、コンテナイメージと WebSocket は×

AI エージェントは、Express のアプリから Bedrock の Claude Haiku 4.5 を呼び、ツールを使わせる形で作りました。

CloudWatch Logs の agent_summary。wallMs 5804、modelWaitMs 4303、processCpuMs 197

ログを見てみると1件5.8秒のうちモデルの応答待ちが4.3秒、ツールの待ちが1.5秒で、CPU を使っていたのは0.2秒だけでした。処理時間のほとんどが待ち時間になっていることがわかります。

エンドポイントの認証を IamAuth にすると、ブラウザから署名なしで開いた場合は 403 が返ってきます。

ブラウザで IamAuth のエンドポイントを開くと 403 Forbidden

DB を使う3層構成では、VPC の egress network connector 経由で Aurora Serverless v2 につなぎ、IAM 認証で接続しました。

メモ帳アプリ。2 件を書き込み、PostgreSQL 17.9 から読み出し

ブラウザのフォームから書き込んだメモが、VPC の中の Aurora に保存され、一覧に表示されています。

注意点として、VPC への接続はリビジョンの設定になるため、deploy コマンドでは付けられません。create-web-function-revision で、接続を設定したリビジョンを作成します。

リビジョンの設定。ネットワークコネクター、タイムアウト 30s、同時 64

カナリアリリース

今回の検証で一番手間がかかったのがカナリアリリースです。
aws lambda-web deploy は新しいリビジョンに100%切り替えてしまうので、create-web-function-revision でリビジョンを作ってから、エンドポイントの重みを変更する方針で進めています。

aws lambda-web update-web-function-endpoint \
  --function-name lwf-verify-ops --endpoint-name dev \
  --revision-weights revisionId=rev-l04as,weight=90 revisionId=rev-x5oct,weight=10

Lambda のエンドポイント dev。リビジョンルーティングが rev-l04as (90)、rev-x5oct (10)

設定自体は4秒で終わりますが、実際に振り分けが効き始めるまでには15〜30秒かかりました。
設定の直後に1,000件流したところ、新しいリビジョンに届いたのは6件だけでした。

Cloud Run の gcloud run services update-traffic --to-revisions では、設定の直後から約1割が新しいリビジョンに振り分けられていたので、ここは Cloud Run のほうが扱いやすいと感じました。

Cloud Run のリビジョン一覧(ロールバック後)。00001 が 100%、00002 が 0%

料金

Lambda Web Functions は、CPU は使った時間だけ、メモリは「使っている量 × 環境がある時間」で課金されます。

ここでメモリが割り当ての 2 GB で計算されるのか、実際に使った量で計算されるのかが気になったので、請求(Cost Explorer)で確認しました。

Cost Explorer。APN1-Lambda-Web-Memory-GB-Second-ARM の使用量 3,951.16 GB-Seconds、$0.02

負荷テスト1時間分の請求は 3,951 GB 秒で、メトリクスから計算した実使用量(約3,800 GB 秒)とほぼ一致しています。
2 GB で計算されていれば約4万3,600 GB 秒になるはずなので、実際に使った量で課金されていることがわかります。

AWS の料金ページに載っている4つのワークロードの例を、東京リージョンの単価で両方に当てはめて試算してみました。

試算。待ちの長い3つは Lambda が最安、短く大量の認可だけ Cloud Run 常時1台が最安

待ち時間が長い処理ほど、Lambda のほうが安くなる結果になりました。
AI エージェントのように、処理時間のほとんどがモデルの応答待ちになる用途では、CPU の課金がほとんど発生しないためです。
逆に、短いリクエストが大量に来るような用途では、Cloud Run のほうが安くなっています。

まとめ

今回は、GA になったばかりの Lambda Web Functions に Next.js をデプロイして、Cloud Run と比較してみました。

Next.js は数行のファイルを追加するだけで動き、コールドスタートも Cloud Run の半分以下だったので、思っていた以上に普通の Web アプリの置き場所として使えると感じました。

個人的には、新しく作る AI エージェントや、外部 API の応答を待つことが多い API から試してみるのがよさそうです。DB を使う場合は、環境がどんどん増える前提で、接続数の絞り方を最初に決めておくと安心です。

デプロイの手順やコマンドも載せているので、ぜひ手元でも試してみてください。

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?