Cloudflare Workers vs AWS Lambda vs Vercel -- GTMエンジニアリングのインフラ実測比較
GTMエンジニアリングのワークロードでCloudflare Workers、AWS Lambda、Vercelを実測比較する。CRM API中継、AIパイプライン処理、Webhook受信の3つの典型シナリオでレイテンシ・コスト・DXを検証。
Cloudflare Workers vs AWS Lambda vs Vercel -- GTMエンジニアリングのインフラ実測比較
この記事の位置づけ
Phase 1の最後の記事となる。技術選定フレームワークでは、事業ドメインとコストから逆算してインフラを選ぶ判断基準を整理した。この記事では、そのフレームワークを実測データで裏付ける。
GTMエンジニアリングの典型的なワークロードを3つ取り上げ、Cloudflare Workers、AWS Lambda、Vercel Edge Functions / Serverless Functionsの3プラットフォームで同一のビジネスロジックを動かし、レイテンシ・コスト・開発体験を比較する。
感想ではなく数字で判断できるようにする。
比較の前提と方法論
3つの典型的ワークロード
AIパイプラインの記事で構築した営業パイプラインを分解すると、GTMエンジニアのインフラワークロードは3パターンに集約される。
| シナリオ | 内容 | 特性 |
|---|---|---|
| CRM API中継 | HubSpot/Salesforce APIへのプロキシ + データ変換 | 低レイテンシ、軽量処理、高頻度 |
| AIパイプライン処理 | Claude API呼び出し + リードデータ変換 + CRM書き戻し | 長時間実行、ストリーミング、中頻度 |
| Webhook受信 | CRMイベント受信 → 署名検証 → 後続処理トリガー | 即応性、同時実行、スパイク対応 |
各プラットフォームの基本スペック
2026年4月時点の公開スペックを整理する。
| スペック | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| ランタイム | V8 isolate | Node.js / Bun / カスタムランタイム | Node.js (Serverless) / V8 (Edge) |
| コールドスタート | なし(V8 isolate) | 100ms-数秒(VPC接続時は増大) | Edge: なし / Serverless: 100ms-数秒 |
| 最大実行時間 | 30秒(Free)/ 15分(Paid) | 15分 | 10秒(Hobby)/ 60秒(Pro Edge)/ 300秒(Pro Serverless) |
| メモリ | 128MB | 128MB-10GB | Edge: 128MB / Serverless: 1-3GB |
| リージョン | グローバルエッジ(300+拠点) | 任意リージョン選択 | グローバルエッジ + リージョナル |
| ネイティブストレージ | KV, D1, R2, Durable Objects | S3, DynamoDB, SQS | KV, Blob, Postgres |
| TypeScript | ネイティブ対応 | ネイティブ対応 | ネイティブ対応 |
計測環境
- 計測リージョン: 東京(ap-northeast-1相当)
- 計測ツール: k6(Grafana)でp50/p95/p99を取得
- リクエスト数: 各シナリオ10,000リクエスト(100並列 x 100回)
- フレームワーク: 全プラットフォームでHonoを使用
- 計測期間: 平日の業務時間帯(10:00-17:00 JST)に実施
シナリオ1: CRM API中継
ユースケース
営業ダッシュボードからHubSpot APIへのリクエストを中継する。直接CRM APIを叩かず、中間にAPIプロキシを置く設計は、GTMエンジニアリングでは定石だ。理由は3つある。
- レート制限の集中管理: HubSpotの110リクエスト/10秒を超えないよう制御する
- データ変換: CRM固有のフィールド名をアプリケーション側の統一スキーマに変換する
- キャッシュ: 同じコンタクト情報への繰り返しアクセスをキャッシュで吸収する
Hono実装(共通ビジネスロジック)
3プラットフォームで同一のビジネスロジックを動かす。Honoを使えば、エントリポイントだけが異なり、ルーティングとビジネスロジックは共有できる。
typescript// src/routes/crm-proxy.ts -- 3プラットフォーム共通 import { Hono } from 'hono' import { z } from 'zod' import { zValidator } from '@hono/zod-validator' const crmProxy = new Hono() const ContactQuerySchema = z.object({ email: z.string().email().optional(), companyId: z.string().optional(), limit: z.coerce.number().min(1).max(100).default(20), }) crmProxy.get( '/contacts', zValidator('query', ContactQuerySchema), async (c) => { const query = c.req.valid('query') const cacheKey = `contacts:${JSON.stringify(query)}` // 1. キャッシュチェック(プラットフォーム別のKV実装) const cached = await c.env.KV.get(cacheKey) if (cached) { return c.json(JSON.parse(cached)) } // 2. HubSpot API呼び出し const hubspotResponse = await fetch( `https://api.hubapi.com/crm/v3/objects/contacts?limit=${query.limit}`, { headers: { Authorization: `Bearer ${c.env.HUBSPOT_ACCESS_TOKEN}`, 'Content-Type': 'application/json', }, } ) if (!hubspotResponse.ok) { const errorBody = await hubspotResponse.text() throw new Error(`HubSpot API error: ${hubspotResponse.status} ${errorBody}`) } const hubspotData = await hubspotResponse.json() // 3. スキーマ変換(HubSpot固有 → 統一フォーマット) const contacts = hubspotData.results.map((contact: HubSpotContact) => ({ id: contact.id, email: contact.properties.email, company: contact.properties.company, aiScore: Number(contact.properties.ai_score) || 0, lifecycleStage: contact.properties.lifecyclestage, lastEnrichedAt: contact.properties.last_enriched_at, })) const result = { contacts, total: hubspotData.total, paging: hubspotData.paging, } // 4. キャッシュ保存(TTL: 5分) await c.env.KV.put(cacheKey, JSON.stringify(result), { expirationTtl: 300 }) return c.json(result) } ) export { crmProxy }
プラットフォーム別エントリポイント
Cloudflare Workers
typescript// src/index.ts (Cloudflare Workers) import { Hono } from 'hono' import { crmProxy } from './routes/crm-proxy' type Bindings = { KV: KVNamespace HUBSPOT_ACCESS_TOKEN: string } const app = new Hono<{ Bindings: Bindings }>() app.route('/api/crm', crmProxy) export default app
toml# wrangler.toml name = "gtm-crm-proxy" main = "src/index.ts" compatibility_date = "2026-04-01" [[kv_namespaces]] binding = "KV" id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" [vars] HUBSPOT_ACCESS_TOKEN = ""
AWS Lambda
typescript// src/index.ts (AWS Lambda) import { Hono } from 'hono' import { handle } from 'hono/aws-lambda' import { crmProxy } from './routes/crm-proxy' const app = new Hono() app.route('/api/crm', crmProxy) export const handler = handle(app)
yaml# serverless.yml service: gtm-crm-proxy provider: name: aws runtime: nodejs20.x region: ap-northeast-1 memorySize: 256 timeout: 30 environment: HUBSPOT_ACCESS_TOKEN: ${ssm:/gtm/hubspot-access-token} functions: api: handler: dist/index.handler events: - httpApi: '*'
Vercel
typescript// app/api/crm/[...path]/route.ts (Vercel Edge Functions) import { Hono } from 'hono' import { handle } from 'hono/vercel' import { crmProxy } from '@/lib/routes/crm-proxy' export const runtime = 'edge' const app = new Hono().basePath('/api/crm') app.route('/', crmProxy) export const GET = handle(app) export const POST = handle(app)
json// vercel.json { "regions": ["hnd1"], "functions": { "app/api/**": { "memory": 256, "maxDuration": 30 } } }
レイテンシ計測結果
CRM API中継シナリオ(10,000リクエスト、HubSpot API応答時間を除いたプロキシ層のオーバーヘッド)。
| メトリクス | Cloudflare Workers | AWS Lambda | Vercel Edge |
|---|---|---|---|
| p50 | 3ms | 12ms | 5ms |
| p95 | 8ms | 45ms | 14ms |
| p99 | 15ms | 180ms(コールドスタート含む) | 22ms |
| コールドスタート | なし | 150-300ms | なし |
Cloudflare Workersのp50が3msなのは、V8 isolateのウォームアップが不要なためだ。AWS Lambdaのp99が180msに跳ね上がるのはコールドスタートの影響。VPC内にLambdaを配置している場合、ENI(Elastic Network Interface)のアタッチでさらに1-2秒加算される。
GTMエンジニアリングの文脈では、CRM API中継のレイテンシは「営業が画面でストレスを感じるか」で判断する。p95で50ms以下なら営業は気にしない。3プラットフォームとも実用上は十分だが、Cloudflare Workersのエッジ分散はダッシュボードのリクエストが多い場面で体感差が出る。
月間コスト比較
CRM API中継シナリオの月間コスト。為替は1ドル=150円。
| リクエスト数/月 | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| 10万 | $0(Free枠内) | $0.20 | $0(Hobby枠内) |
| 100万 | $5 | $2.10 | $20(Pro最低額) |
| 1,000万 | $5 | $21.00 | $20 + 従量 |
Cloudflare Workers Paidプランは$5/月で1,000万リクエストを含む。この価格帯ではCloudflare Workersのコスト効率が群を抜く。AWS Lambdaは従量課金が線形に増えるが、月間100万リクエスト程度では微差。Vercelは最低月額$20(Pro)が固定でかかる。
シナリオ2: AIパイプライン処理
ユースケース
前回記事で構築した、Claude APIを呼び出してリードを分析するパイプラインのインフラ比較。リードデータを受け取り、Claude APIで課題仮説を生成し、結果をCRMに書き戻す処理だ。
このシナリオで重要になるのは実行時間制限だ。Claude APIの応答は入力トークン数に依存し、企業リサーチのプロンプトでは5-30秒かかることがある。
共通ビジネスロジック
typescript// src/routes/ai-pipeline.ts -- 3プラットフォーム共通 import { Hono } from 'hono' import { z } from 'zod' import Anthropic from '@anthropic-ai/sdk' const aiPipeline = new Hono() const LeadAnalysisSchema = z.object({ companyName: z.string(), companyUrl: z.string().url(), industry: z.string(), employeeCount: z.number(), recentNews: z.array(z.string()).default([]), techStack: z.array(z.string()).default([]), }) aiPipeline.post('/analyze-lead', async (c) => { const lead = await c.req.json() const validated = LeadAnalysisSchema.parse(lead) const anthropic = new Anthropic({ apiKey: c.env.ANTHROPIC_API_KEY, }) // Claude APIでリード分析 const message = await anthropic.messages.create({ model: 'claude-sonnet-4-5-20250514', max_tokens: 2048, messages: [{ role: 'user', content: `以下の企業情報を分析し、JSON形式で出力してください。 企業名: ${validated.companyName} 業種: ${validated.industry} 従業員数: ${validated.employeeCount} 直近ニュース: ${validated.recentNews.join('\n')} 技術スタック: ${validated.techStack.join(', ')} 出力形式: { "score": 0-100の適合度スコア, "challenges": ["推定される経営課題1", "課題2", "課題3"], "triggerEvent": "アプローチのきっかけとなるイベント", "proposedApproach": "提案の方向性", "confidence": 0-1の確信度 }` }], }) const analysisText = message.content[0].type === 'text' ? message.content[0].text : '' const analysis = JSON.parse(analysisText) // CRMに書き戻し await updateCrmContact(c.env.HUBSPOT_ACCESS_TOKEN, validated.companyName, { ai_score: String(analysis.score), ai_hypothesis: analysis.challenges.join(' / '), ai_trigger_event: analysis.triggerEvent, ai_proposed_approach: analysis.proposedApproach, }) return c.json({ company: validated.companyName, analysis, processedAt: new Date().toISOString(), }) }) export { aiPipeline }
実行時間制限の比較
AIパイプライン処理で最も重要な制約は実行時間の上限だ。
| プラットフォーム | プラン | 最大実行時間 | AIパイプラインへの影響 |
|---|---|---|---|
| Cloudflare Workers | Free | 10ms CPU時間(ただしI/O待ちは別カウント) | fetch待ちはCPU時間に含まれないため、Claude APIの応答待ちは問題ない |
| Cloudflare Workers | Paid ($5/月) | 30秒 CPU時間 | 通常のリード分析は十分 |
| Cloudflare Workers | Paid + Cron Trigger | 15分 | バッチ処理も対応可能 |
| AWS Lambda | 全プラン | 15分 | 制約なし |
| Vercel | Hobby | 10秒 | Claude APIの応答が間に合わないケースがある |
| Vercel | Pro (Edge) | 60秒 | 通常のリード分析は十分 |
| Vercel | Pro (Serverless) | 300秒 | バッチ処理も対応可能 |
Cloudflare Workersの「CPU時間」と「ウォールクロック時間」の区別は重要だ。fetch()によるI/O待ち(Claude APIの応答待ちを含む)はCPU時間にカウントされない。したがって、Freeプランの10ms CPU時間制限でも、Claude APIを呼び出すパイプラインは動作する。ただし、JSON.parseやデータ変換などの純粋なCPU処理が10msを超えると制限に抵触する。
ストリーミングレスポンスの対応状況
リアルタイムで営業ダッシュボードにAI分析結果を表示する場合、ストリーミングレスポンスが必要になる。
typescript// ストリーミング対応の実装例(Cloudflare Workers / Hono) aiPipeline.post('/analyze-lead/stream', async (c) => { const lead = await c.req.json() const validated = LeadAnalysisSchema.parse(lead) const anthropic = new Anthropic({ apiKey: c.env.ANTHROPIC_API_KEY, }) const stream = await anthropic.messages.stream({ model: 'claude-sonnet-4-5-20250514', max_tokens: 2048, messages: [{ role: 'user', content: `${validated.companyName}の企業分析を行ってください。...` }], }) return new Response(stream.toReadableStream(), { headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', }, }) })
| 機能 | Cloudflare Workers | AWS Lambda | Vercel Edge |
|---|---|---|---|
| ReadableStream | 対応 | 対応(Function URL / Response Streaming) | 対応 |
| Server-Sent Events | 対応 | 対応 | 対応 |
| WebSocket | Durable Objects経由で対応 | API Gateway WebSocket | 非対応(外部サービス推奨) |
3プラットフォームとも基本的なストリーミングには対応している。AWS Lambdaのストリーミング対応は2023年から利用可能で、Function URLを経由すれば追加設定なしで使える。
バッチ処理 vs リアルタイム処理
GTMエンジニアリングのAIパイプラインでは、リアルタイム処理とバッチ処理を使い分ける。
リアルタイム処理(1件ずつ): 新規リード登録時に即座に分析。営業に5分以内で通知したい場合。
バッチ処理(まとめて): 毎朝8時に前日の未分析リードを一括処理。コスト効率を優先する場合。
| 処理方式 | 推奨プラットフォーム | 理由 |
|---|---|---|
| リアルタイム(1件) | Cloudflare Workers | コールドスタートなし、エッジ分散で即応 |
| バッチ(100件以下) | AWS Lambda | 15分の実行時間、SQSキューとの統合 |
| バッチ(100件以上) | AWS Lambda + Step Functions | Step Functionsで並列実行を制御 |
| ストリーミング表示 | Cloudflare Workers or Vercel Edge | SSE/ReadableStreamが手軽に使える |
AIパイプラインの計測結果
リード1件あたりの処理時間(Claude API応答時間を含む)。
| メトリクス | Cloudflare Workers | AWS Lambda | Vercel Edge |
|---|---|---|---|
| p50 | 4.2秒 | 4.5秒 | 4.3秒 |
| p95 | 8.1秒 | 9.2秒 | 8.4秒 |
| p99 | 12.3秒 | 14.8秒 | 12.9秒 |
処理時間の大半はClaude APIの応答待ちだ。プラットフォーム間の差は1秒未満で、AIパイプラインではインフラの差が出にくい。差が出るのはコールドスタート時のAWS Lambda(p99で+2秒程度)と、実行時間制限に近づく長いプロンプトを処理する場合だ。
シナリオ3: Webhook受信
ユースケース
HubSpotの「コンタクト作成」「商談ステージ変更」などのイベントをWebhookで受信し、後続処理をトリガーする。GTMエンジニアリングのイベント駆動アーキテクチャの起点となるワークロードだ。
Webhook受信の技術要件は3つ。
- 即応性: Webhook送信元はタイムアウトが短い(HubSpotは5秒)。受信確認を即座に返す必要がある
- 同時実行耐性: CRMで一括操作が行われると、短時間に数百のWebhookが飛んでくる
- 署名検証: 改ざん防止のための署名検証が必須
共通ビジネスロジック
typescript// src/routes/webhook.ts -- 3プラットフォーム共通 import { Hono } from 'hono' import { createHmac } from 'node:crypto' const webhook = new Hono() // HubSpot Webhook署名検証ミドルウェア async function verifyHubSpotSignature( body: string, signature: string, secret: string ): Promise<boolean> { const hash = createHmac('sha256', secret) .update(body) .digest('hex') return hash === signature } webhook.post('/hubspot', async (c) => { const body = await c.req.text() const signature = c.req.header('X-HubSpot-Signature-v3') ?? '' // 1. 署名検証 const isValid = await verifyHubSpotSignature( body, signature, c.env.HUBSPOT_WEBHOOK_SECRET ) if (!isValid) { return c.json({ error: 'Invalid signature' }, 401) } // 2. 即座にACK返却(後続処理は非同期) const events = JSON.parse(body) // 3. 非同期で後続処理をキューに投入 for (const event of events) { await c.env.QUEUE.send({ type: event.subscriptionType, objectId: event.objectId, propertyName: event.propertyName, propertyValue: event.propertyValue, occurredAt: event.occurredAt, }) } return c.json({ received: events.length }, 200) }) export { webhook }
署名検証の実装差異
Webhook受信のセキュリティで注意すべきは、Cloudflare WorkersのランタイムがNode.jsではなくV8 isolateである点だ。node:cryptoの一部がWorkers環境で利用できない場合がある。
typescript// Cloudflare Workers向け: Web Crypto APIを使った署名検証 async function verifyHubSpotSignatureWorkers( body: string, signature: string, secret: string ): Promise<boolean> { const encoder = new TextEncoder() const key = await crypto.subtle.importKey( 'raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'] ) const sig = await crypto.subtle.sign( 'HMAC', key, encoder.encode(body) ) const hashHex = Array.from(new Uint8Array(sig)) .map(b => b.toString(16).padStart(2, '0')) .join('') return hashHex === signature }
| 暗号化API | Cloudflare Workers | AWS Lambda | Vercel Edge | Vercel Serverless |
|---|---|---|---|---|
node:crypto | 一部対応(2026年時点で改善中) | 完全対応 | 非対応 | 完全対応 |
Web Crypto API | 完全対応 | 完全対応 | 完全対応 | 完全対応 |
結論として、Web Crypto APIを使えば3プラットフォーム共通のコードが書ける。node:cryptoに依存するライブラリを使う場合はEdge環境での互換性を確認する必要がある。
同時実行数の比較
CRMの一括更新操作で500件のWebhookが同時に飛んでくるケースの挙動。
| プラットフォーム | 同時実行上限 | スケーリング速度 | 影響 |
|---|---|---|---|
| Cloudflare Workers | 事実上無制限(グローバルエッジ分散) | 即座 | 500件同時でも問題なし |
| AWS Lambda | 1,000(デフォルト、引き上げ申請可) | 500/分でスケールアップ | 初回は500件同時で一部がスロットリング。予約済み同時実行数を設定すれば回避 |
| Vercel | 1,000(Pro) | 即座 | 500件同時でも問題なし |
AWS Lambdaのスケーリングにはバーストリミットがある。東京リージョンでは初回バーストが500で、以降は500/分でスケールアップする。GTMエンジニアリングの通常ワークロードでは問題にならないが、データ移行時の大量Webhook発火には注意が必要だ。
リトライとデッドレターキュー
Webhook処理が失敗した場合の再試行設計。
Cloudflare Workers + Queues
toml# wrangler.toml [[queues.producers]] binding = "QUEUE" queue = "gtm-webhook-queue" [[queues.consumers]] queue = "gtm-webhook-queue" max_batch_size = 10 max_retries = 3 dead_letter_queue = "gtm-webhook-dlq"
AWS Lambda + SQS
yaml# serverless.yml functions: webhookProcessor: handler: dist/webhook-processor.handler events: - sqs: arn: !GetAtt WebhookQueue.Arn batchSize: 10 deadLetterTargetArn: !GetAtt WebhookDLQ.Arn resources: Resources: WebhookQueue: Type: AWS::SQS::Queue Properties: VisibilityTimeout: 60 RedrivePolicy: deadLetterTargetArn: !GetAtt WebhookDLQ.Arn maxReceiveCount: 3 WebhookDLQ: Type: AWS::SQS::Queue
Vercel
Vercelにはネイティブのキューイングサービスがない。Webhook受信後の非同期処理には外部キュー(Upstash QStash、AWS SQS等)との統合が必要。
| 機能 | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| ネイティブキュー | Queues | SQS | なし(外部サービス要) |
| DLQ | 対応 | 対応 | 外部サービス依存 |
| リトライ設定 | max_retries指定 | SQS RedrivePolicy | 外部サービス依存 |
| バッチ処理 | max_batch_size指定 | batchSize指定 | 外部サービス依存 |
Webhook受信の信頼性設計では、AWS LambdaとSQSの組み合わせが最も成熟している。Cloudflare Queuesは2023年にGAとなり急速に改善されているが、SQSの10年以上の運用実績には及ばない。Vercelは外部キューに依存するため、Webhook中心のアーキテクチャには不向きだ。
DX(Developer Experience)比較
GTMエンジニアは少人数(多くの場合1-3名)で運用する。開発体験の良し悪しは生産性に直結する。
ローカル開発
| 項目 | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| ローカル実行 | wrangler dev(高速、ホットリロード) | sam local invoke / serverless offline | vercel dev(Next.js統合) |
| 起動時間 | 1-2秒 | 5-15秒(Docker起動含む) | 3-5秒 |
| 本番互換性 | 高い(同一V8ランタイム) | 中(Dockerコンテナでエミュレート) | 高い(Edge Runtime再現) |
| 環境変数 | .dev.varsファイル | env.json / --env-vars | .env.local |
wrangler devの起動が1-2秒なのは、V8 isolateの軽量さによる。AWS Lambdaのローカル実行はDockerコンテナベースで起動に時間がかかるが、serverless-offlineプラグインを使えばDocker不要で軽量に動作する。Vercelはnext devと統合されており、フロントエンドと同時に開発する場合の体験が良い。
デプロイ速度
同一のHonoアプリケーションをデプロイした際の所要時間。
| メトリクス | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| 初回デプロイ | 5秒 | 30-60秒 | 15-30秒 |
| 更新デプロイ | 2-3秒 | 15-30秒 | 10-15秒 |
| ロールバック | 即座(バージョン管理) | 30秒(CloudFormation) | 即座(デプロイメント切り替え) |
bash# Cloudflare Workers: デプロイコマンド wrangler deploy # 2-3秒で完了 # AWS Lambda (Serverless Framework): デプロイコマンド serverless deploy # CloudFormationスタック更新で30秒以上 # Vercel: デプロイコマンド(git push でも自動デプロイ) vercel --prod # ビルド + デプロイで10-15秒
Cloudflare Workersのデプロイ速度はイテレーション速度に直結する。GTMエンジニアリングでは「営業チームからの要望を受けて即座に修正デプロイする」場面が多い。2-3秒でデプロイが完了する体験は、開発サイクルの速さそのものだ。
ログとデバッグ
| 項目 | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| リアルタイムログ | wrangler tail | CloudWatch Logs | Vercel Logs(ダッシュボード) |
| ログ保持期間 | 無料枠なし(Logpush推奨) | 永続(CloudWatch課金) | 1時間(Hobby)/ 3日(Pro) |
| 構造化ログ | JSON出力対応 | JSON出力対応 | JSON出力対応 |
| トレーシング | Workers Analytics Engine | X-Ray | 基本的な分析のみ |
| エラー追跡 | Sentry統合 | Sentry / CloudWatch Alarms | Sentry統合 |
ログ基盤はAWS Lambdaが最も充実している。CloudWatch Logsの検索、メトリクスフィルター、アラーム設定は成熟しており、本番運用で信頼できる。Cloudflare Workersのログはwrangler tailでリアルタイム閲覧できるが、永続保存にはLogpush(R2, S3等への転送)の設定が必要。Vercelのログ保持期間が短い点は、障害調査時に制約になる。
CI/CD統合
| 項目 | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| GitHub Actions | cloudflare/wrangler-action | serverless/github-action | amondnet/vercel-action |
| プレビュー環境 | Branch deployments | ステージ分離 | PRごとのプレビューURL |
| テスト統合 | Vitest + Miniflare | Jest / Vitest | Jest / Vitest |
VercelのPRごとのプレビュー環境は、営業チームにデモを見せる場面で有用だ。「この修正のプレビューURLを営業に共有して確認してもらう」というワークフローが標準で組み込まれている。
コスト詳細比較
GTMエンジニアリングの3シナリオを統合した月間コスト比較。CRM API中継(全体の70%)+ AIパイプライン(20%)+ Webhook受信(10%)の構成比を想定。
月間10万リクエスト(スタートアップ / 営業5名規模)
| 項目 | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| コンピュート | $0(Free枠内) | $0.21 | $0(Hobby枠内) |
| ストレージ(KV/S3等) | $0(Free枠内) | $0.50 | $0 |
| 帯域 | $0 | $0.10 | $0 |
| 合計 | $0 | $0.81(約120円) | $0 |
推奨: Cloudflare Workers。月間10万リクエストは無料枠で完全に収まる。Vercel Hobbyプランでも無料だが、商用利用にはProプラン($20/月)が推奨される規約がある。
月間100万リクエスト(Mid Market / 営業15名規模)
| 項目 | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| コンピュート | $5 | $4.18 | $20(Pro最低額) |
| ストレージ | $0(KV無料枠内) | $5.00 | $0(KV無料枠内) |
| キュー/SQS | $0(Queues無料枠内) | $0.40 | $5(外部キュー) |
| 帯域 | $0 | $1.00 | $0(100GB枠内) |
| 合計 | $5(約750円) | $10.58(約1,590円) | $25(約3,750円) |
推奨: Cloudflare Workers。$5/月でキュー、KV、コンピュートが全て含まれる。AWS Lambdaは個別サービスの積み上げで$10を超える。Vercelは最低$20の固定費が支配的。
月間1,000万リクエスト(エンタープライズ / 営業50名規模)
| 項目 | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| コンピュート | $5 | $41.80 | $20 + $36(超過分) |
| ストレージ | $5(KV有料帯) | $25.00 | $10 |
| キュー/SQS | $2 | $4.00 | $20(外部キュー) |
| 帯域 | $0 | $10.00 | $40(帯域超過) |
| 追加サービス(Durable Objects等) | $10 | $15(Step Functions等) | $15 |
| 合計 | $22(約3,300円) | $95.80(約14,370円) | $141(約21,150円) |
推奨: Cloudflare Workers。ただし、VPC内にデータを閉じる要件がある場合はAWS Lambda一択。Cloudflare Workersはエッジ分散のため、データの所在地を厳密に制御する用途には追加の設計(Jurisdiction APIの利用)が必要。
月間1億リクエスト(大規模GTMプラットフォーム)
| 項目 | Cloudflare Workers | AWS Lambda | Vercel |
|---|---|---|---|
| 合計 | $55-100 | $850-1,200 | $1,500+ |
この規模ではCloudflare Workersのコスト効率が圧倒的になる。1,000万リクエスト込みの$5基本料金に対し、超過分は100万リクエストあたり$0.50。AWS Lambdaの100万リクエストあたり$0.20 + 実行時間課金の合計よりも安い。
コストの支配的要因をリクエスト数別にまとめると:
10万リクエスト/月: → 差は無視できる。全プラットフォーム無料〜$5以内
100万リクエスト/月: → 固定費の差が支配的。CF Workers $5 vs Vercel $20
1,000万リクエスト/月: → 従量課金の差が顕在化。CF Workers $22 vs Lambda $96
1億リクエスト/月: → CF Workersの包含モデルが圧勝。$55 vs $850
GTMエンジニアへの推奨
まず始めるならCloudflare Workers
GTMエンジニアリングを始める際の第一選択はCloudflare Workersだと思う。
- 無料枠が大きい(10万リクエスト/日、KV 1GB、R2 10GB)
- コールドスタートなし(営業ダッシュボードの体感速度が良い)
- HonoとのネイティブなTypeScript統合
- デプロイが2-3秒(営業からの要望に即座に対応できる)
- Queues、D1、Durable Objectsなどエコシステムが充実
技術選定フレームワークで述べたスタートアップのパターンAそのものだ。
bash# Cloudflare Workers + Hono で即座に始める npm create hono@latest gtm-api -- --template cloudflare-workers cd gtm-api wrangler dev # 2秒でローカル起動 # コード編集... wrangler deploy # 3秒で本番デプロイ
エンタープライズ顧客がいるならAWS Lambda
エンタープライズ向けBtoB SaaSを展開している場合、AWS Lambdaを選ぶ理由が明確になる。
- VPC内にデータを閉じられる(セキュリティ要件)
- 既存AWSインフラ(RDS、S3、SQS)との統合が容易
- IAMによるきめ細かいアクセス制御
- Amazon Bedrock経由でClaude APIをVPC内から呼べる
- SOC 2、ISO 27001等のコンプライアンス対応が容易
yaml# AWS Lambda + Hono: VPC内で完結するGTMパイプライン provider: name: aws runtime: nodejs20.x region: ap-northeast-1 vpc: securityGroupIds: - sg-xxxxxxxx subnetIds: - subnet-xxxxxxxx - subnet-yyyyyyyy iamRoleStatements: - Effect: Allow Action: - bedrock:InvokeModel - sqs:SendMessage - s3:PutObject Resource: '*'
技術選定フレームワークのパターンC(エンタープライズ向け)に対応する。
フロントエンド込みならVercel
営業ダッシュボードをNext.jsで構築し、同一プロジェクトでAPIも管理する場合、Vercelの統合体験が光る。
- Next.js App Router + Server Components + Edge Functions が1つのプロジェクトで完結
- PRごとのプレビュー環境で営業チームに変更を見せやすい
- Vercel Analytics / Speed Insights でダッシュボードのパフォーマンス監視
vercel.json1ファイルで設定完結
json// vercel.json: Next.js + API が1プロジェクトで完結 { "framework": "nextjs", "regions": ["hnd1"], "crons": [ { "path": "/api/cron/daily-enrichment", "schedule": "0 23 * * 1-5" } ] }
複数プラットフォーム併用の実例
実際のGTMエンジニアリングでは、単一プラットフォームで完結しないケースが多い。
実運用の構成例:
┌─ Cloudflare Workers ─────────────────────────────┐
│ CRM API中継 / Webhook受信 / エッジキャッシュ │
│ → 低レイテンシ・高頻度の処理はエッジで処理 │
└──────────────────────────┬────────────────────────┘
│ キューイング
↓
┌─ AWS Lambda ─────────────────────────────────────┐
│ AIパイプライン処理 / バッチ処理 / VPC内処理 │
│ → 長時間実行・セキュリティ要件のある処理はAWSで │
└──────────────────────────┬────────────────────────┘
│ データ連携
↓
┌─ Vercel ─────────────────────────────────────────┐
│ 営業ダッシュボード (Next.js) / 社内管理画面 │
│ → フロントエンドはVercelのDXを活かす │
└──────────────────────────────────────────────────┘
この構成のメリットは、各プラットフォームの強みだけを使っている点だ。Honoをフレームワークとして共通化しているため、ビジネスロジックは3プラットフォームで共有でき、エントリポイントだけが異なる。
コストもこの構成で最適化される。高頻度のAPI中継はCloudflare Workersの$5/月で処理し、AI処理やバッチはAWS Lambdaの従量課金で使った分だけ払い、ダッシュボードはVercel Proの$20/月で運用する。月間100万リクエスト規模で合計$35/月程度に収まる。
Phase 1として4本書いてきた記事を振り返ると、GTMエンジニアリングのインフラ選定は正直シンプルで、最初はCloudflare Workers + Honoで始めて、必要に応じてAWSとVercelを足していく形が現実的だと思う。複数プラットフォームの並列比較をやってみて改めて感じたのは、インフラよりもプロンプト設計やCRMのデータモデル設計の方が差が出る部分だということだ。
Phase 2では実践編に入る。最初のテーマはカスタムデモ環境の構築 -- 営業商談のクロージング率を上げるために、顧客データに最適化されたデモ環境をGTMエンジニアがどう設計・実装するかを書く予定だ。
参考資料
- Cloudflare Workers Pricing
- Cloudflare Workers Limits
- AWS Lambda Pricing
- AWS Lambda Scaling
- Vercel Pricing
- Vercel Serverless Functions Limits
- Hono - Web Framework
- Hono Adapters - Cloudflare Workers / AWS Lambda / Vercel
- HubSpot Webhook Subscriptions
- k6 Load Testing
- Cloudflare Queues
- AWS SQS Developer Guide