Use Cases (更新: 2026/6/2)

Claude Code × AWS Lambda 完全ガイド|関数生成からデプロイ自動化まで

Claude CodeでAWS Lambdaを安全に実装。Node.js 24、SAM、IAM、API Gateway、S3、ログ、失敗対策まで実例で解説。

Claude Code × AWS Lambda 完全ガイド|関数生成からデプロイ自動化まで

AWS Lambda 開発でこんな経験はありませんか? ハンドラーの型定義が面倒、IAMポリシーを毎回調べながら書いている、SAM テンプレートの書き方を忘れた……。Claude Code はこれら全てを一度に解決します

Lambda 関数の実装からIAMポリシー生成、ローカルテスト、本番デプロイまで、Claude Code を使った爆速 AWS Lambda 開発の全工程を実例コードで解説します。

なぜ Claude Code × AWS Lambda なのか

Lambda 開発の「面倒な部分」は実はほとんどがボイラープレートです。

  • ハンドラー関数の型定義 (APIGatewayProxyHandler, S3Handler …)
  • エラーハンドリングとレスポンス形式
  • IAM ポリシーの最小権限設計
  • SAM / CloudFormation テンプレートの記述
  • ローカルテスト環境の設定

Claude Code はこれらを 「こういう Lambda が欲しい」の一言で生成してくれます。さらに AWS CLI や SAM CLI と組み合わせれば、コード生成からデプロイまでを一気に走らせることができます。

環境セットアップ

# 必要なツールの確認
aws --version        # AWS CLI v2
sam --version        # SAM CLI 1.100+
node --version       # Node.js 24+

# AWS 認証情報の設定 (未設定の場合)
aws configure
# → Access Key ID, Secret Access Key, Region (ap-northeast-1), Output (json)
<!-- CLAUDE.md に追記 -->
## AWS 設定
- デフォルトリージョン: ap-northeast-1 (東京)
- Lambda ランタイム: nodejs24.x
- デプロイツール: AWS SAM
- ソースディレクトリ: src/functions/
- SAM テンプレート: template.yaml
- スタック名: my-app-{dev|staging|prod}

## IAM ポリシー方針
- 最小権限の原則を厳守
- ワイルドカード (*) は使わない
- リソース ARN は具体的に指定する

実装例1: API Gateway + Lambda (REST API)

最も基本的なパターン。HTTP リクエストを受けて処理する Lambda です。

Claude Code への指示

claude -p "
/users/{userId} に GET リクエストが来たら
DynamoDB の Users テーブルからユーザー情報を取得して返す
Lambda 関数を TypeScript で実装して。

- ランタイム: Node.js 24
- テーブル名: UsersTable (環境変数で受け取る)
- エラーハンドリング: 404/500 を適切に返す
- 型定義: @types/aws-lambda を使う
- src/functions/getUser/index.ts に出力
"

生成される実装例

// src/functions/getUser/index.ts
import {
  APIGatewayProxyHandler,
  APIGatewayProxyResult,
} from "aws-lambda";
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, GetCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: process.env.AWS_REGION });
const ddb = DynamoDBDocumentClient.from(client);

const response = (statusCode: number, body: unknown): APIGatewayProxyResult => ({
  statusCode,
  headers: {
    "Content-Type": "application/json",
    "Access-Control-Allow-Origin": "*",
  },
  body: JSON.stringify(body),
});

export const handler: APIGatewayProxyHandler = async (event) => {
  const userId = event.pathParameters?.userId;

  if (!userId) {
    return response(400, { error: "userId is required" });
  }

  try {
    const result = await ddb.send(
      new GetCommand({
        TableName: process.env.USERS_TABLE!,
        Key: { userId },
      })
    );

    if (!result.Item) {
      return response(404, { error: `User '${userId}' not found` });
    }

    return response(200, result.Item);
  } catch (err) {
    console.error("DynamoDB error:", err);
    return response(500, { error: "Internal server error" });
  }
};

SAM テンプレートも自動生成

# template.yaml (抜粋)
GetUserFunction:
  Type: AWS::Serverless::Function
  Properties:
    Handler: src/functions/getUser/index.handler
    Runtime: nodejs24.x
    Timeout: 10
    Environment:
      Variables:
        USERS_TABLE: !Ref UsersTable
    Policies:
      - DynamoDBReadPolicy:
          TableName: !Ref UsersTable
    Events:
      GetUserApi:
        Type: Api
        Properties:
          Path: /users/{userId}
          Method: GET

UsersTable:
  Type: AWS::DynamoDB::Table
  Properties:
    TableName: !Sub "${AWS::StackName}-users"
    BillingMode: PAY_PER_REQUEST
    AttributeDefinitions:
      - AttributeName: userId
        AttributeType: S
    KeySchema:
      - AttributeName: userId
        KeyType: HASH

実装例2: S3 イベントトリガー Lambda

ファイルアップロードをトリガーに処理を走らせる Lambda。

// src/functions/generateThumbnail/index.ts
import { S3Handler } from "aws-lambda";
import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import sharp from "sharp";

const s3 = new S3Client({ region: process.env.AWS_REGION });

export const handler: S3Handler = async (event) => {
  const record = event.Records[0];
  const bucket = record.s3.bucket.name;
  const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, " "));

  // thumbnails/ プレフィックスは無視 (無限ループ防止)
  if (key.startsWith("thumbnails/")) return;

  const { Body } = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
  const buffer = Buffer.from(await Body!.transformToByteArray());

  const thumbnail = await sharp(buffer)
    .resize(200, 200, { fit: "cover" })
    .webp({ quality: 85 })
    .toBuffer();

  const thumbnailKey = `thumbnails/${key.replace(/\.[^.]+$/, ".webp")}`;
  await s3.send(
    new PutObjectCommand({
      Bucket: bucket,
      Key: thumbnailKey,
      Body: thumbnail,
      ContentType: "image/webp",
    })
  );

  console.log(`Thumbnail created: s3://${bucket}/${thumbnailKey}`);
};

実装例3: スケジュール実行 Lambda (EventBridge)

# template.yaml の EventBridge 設定
SendReminderFunction:
  Type: AWS::Serverless::Function
  Properties:
    Handler: src/functions/sendReminder/index.handler
    Runtime: nodejs24.x
    Timeout: 300
    Environment:
      Variables:
        DATABASE_URL: !Sub "{{resolve:secretsmanager:${AWS::StackName}/database-url}}"
        RESEND_API_KEY: !Sub "{{resolve:secretsmanager:${AWS::StackName}/resend-api-key}}"
    Events:
      DailyReminder:
        Type: Schedule
        Properties:
          Schedule: cron(0 0 * * ? *)  # UTC 0:00 = JST 9:00

IAM ポリシーを Claude Code に設計させる

claude -p "
以下の Lambda が必要な最小権限 IAM ポリシーを JSON で生成:
- S3 my-uploads から GetObject
- DynamoDB ProcessingJobs に PutItem/UpdateItem
- SQS ProcessingQueue に SendMessage
- CloudWatch Logs に書き込み

ARN はリソース名から推測して具体的に記述すること。
"
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": "arn:aws:s3:::my-uploads/*"
    },
    {
      "Effect": "Allow",
      "Action": ["dynamodb:PutItem", "dynamodb:UpdateItem"],
      "Resource": "arn:aws:dynamodb:ap-northeast-1:*:table/ProcessingJobs"
    },
    {
      "Effect": "Allow",
      "Action": ["sqs:SendMessage"],
      "Resource": "arn:aws:sqs:ap-northeast-1:*:ProcessingQueue"
    },
    {
      "Effect": "Allow",
      "Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
      "Resource": "arn:aws:logs:*:*:log-group:/aws/lambda/*"
    }
  ]
}

ローカルテストと本番デプロイ

# ビルド
sam build

# ローカルで API 起動
sam local start-api --port 3001

# 単発テスト
sam local invoke GetUserFunction --event events/get-user.json

# Claude Code で一括実行
claude -p "
sam build を実行し、
sam local invoke GetUserFunction --event events/test-get-user.json で結果確認。
問題なければ sam deploy --config-env dev を実行。
"

落とし穴5選

1. コールドスタートを考慮しない初期化

// ❌ ハンドラー内で毎回クライアントを生成
export const handler = async () => {
  const ddb = new DynamoDBClient({});  // ← 毎回インスタンス化
};

// ✅ モジュールスコープで1度だけ初期化
const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({}));
export const handler = async () => { /* ddb を再利用 */ };

2. タイムアウトをデフォルト(3秒)のまま DynamoDB + 外部API なら最低10-30秒。処理内容に合わせて設定必須。

3. Secrets を環境変数直書き

# ❌ テンプレートに直書き
Environment:
  Variables:
    DB_PASSWORD: "my-secret"

# ✅ Secrets Manager 経由
Environment:
  Variables:
    DB_PASSWORD: !Sub "{{resolve:secretsmanager:myapp/db-password}}"

4. VPC Lambda のコールドスタート RDS 接続目的で VPC に入れると コールドスタートが数秒延びます。Provisioned Concurrency または RDS Proxy で対処。

5. 巨大なデプロイパッケージ node_modules ごとパッケージすると250MBの上限に当たります。共通ライブラリは Lambda Layer に分離しましょう。

まとめ

タスクClaude Code の貢献
ハンドラー実装型定義・エラー処理・ロジックを一発生成
SAM テンプレートイベント・IAM・環境変数を自動出力
IAM ポリシー最小権限設計を正確に生成
ローカルテストsam invoke 実行と結果判断を自動化
デプロイbuild + deploy を一連で実行

Lambda 開発で最も時間を食う「型定義とテンプレート記述」を Claude Code が丸ごと引き受けます。ビジネスロジックに集中できる環境が実装速度を3-5倍に押し上げます。

Lambdaが向く場面と向かない場面

Lambdaは、短時間で終わり、入力と出力が明確で、失敗時に再実行しても安全な処理に向いています。実例は、注文取得API、S3へアップロードされた画像の加工、EventBridgeによる日次集計、StripeやGitHubのWebhook受信です。反対に、常駐プロセス、長時間の動画変換、低遅延の常時接続、大きなモデルをメモリに置き続ける処理は、ECS/Fargate、App Runner、Step Functions、EC2も比較します。Claude Codeには「Lambdaにする理由」と「Lambdaにしない理由」を両方書かせると、無理なサーバーレス化を避けられます。

用語を平易に整理

用語平易な説明
handlerLambdaが実際に呼び出す関数です。API GatewayならHTTPリクエスト、S3ならファイル作成イベントを受け取ります。
eventLambdaへ渡されるJSONです。API Gateway、S3、EventBridgeで形が違います。
least privilege最小権限。必要なActionを必要なResourceだけに許可する考え方です。
cold start新しい実行環境が起動する初回だけ遅くなる現象です。依存が大きいほど目立ちます。
idempotency冪等性。同じイベントが2回来ても、支払い、メール、DB書き込みが二重にならない性質です。

Node.js 24でコピペ検証できる単体テスト

// test/getUser.test.ts
import { describe, expect, it, vi } from "vitest";
import type { APIGatewayProxyEvent } from "aws-lambda";

const mockSend = vi.fn();
vi.mock("@aws-sdk/lib-dynamodb", async () => {
  const actual = await vi.importActual<typeof import("@aws-sdk/lib-dynamodb")>("@aws-sdk/lib-dynamodb");
  return { ...actual, DynamoDBDocumentClient: { from: () => ({ send: mockSend }) } };
});

const { handler } = await import("../src/functions/getUser/index");

function event(userId?: string): APIGatewayProxyEvent {
  return {
    pathParameters: userId ? { userId } : null,
    httpMethod: "GET",
    path: userId ? "/users/" + userId : "/users",
    headers: {},
    multiValueHeaders: {},
    queryStringParameters: null,
    multiValueQueryStringParameters: null,
    body: null,
    isBase64Encoded: false,
    requestContext: {} as APIGatewayProxyEvent["requestContext"],
    resource: "/users/{userId}",
    stageVariables: null,
  };
}

describe("getUser Lambda", () => {
  it("returns 200 when the user exists", async () => {
    process.env.USERS_TABLE = "UsersTable";
    mockSend.mockResolvedValueOnce({ Item: { userId: "u-1", name: "Masa" } });

    const res = await handler(event("u-1"), {} as never, vi.fn());

    expect(res.statusCode).toBe(200);
    expect(JSON.parse(res.body).userId).toBe("u-1");
  });

  it("returns 400 when path parameter is missing", async () => {
    const res = await handler(event(), {} as never, vi.fn());
    expect(res.statusCode).toBe(400);
  });
});

API Gateway、S3、EventBridgeでイベント形状を分ける

API GatewayはHTTPレスポンスのstatusCodebodyが必要です。S3はRecords配列のbucket/keyを読みます。EventBridgeはsourcedetail-typedetailを見るのが基本です。型を混ぜると、ローカルでは動いても本番イベントで壊れます。Claude Codeへの指示では「HTTP API v2」「S3 ObjectCreated」「EventBridge schedule」のようにトリガー名を具体化してください。

環境変数、Secrets Manager、IAM最小権限

環境変数はUSERS_TABLEAPP_STAGEのような設定値に使います。APIキー、DBパスワード、Webhook署名シークレットはSecrets Managerへ置き、LambdaにはSecret ARNだけを渡します。IAMはdynamodb:GetItems3:GetObjectのようにActionを絞り、Resourceは具体的なARNにします。Claude CodeがResource: "*"s3:*を出したら、最小権限レビューをやり直します。

CloudWatch Logs、リトライ、冪等性

CloudWatch LogsはLambdaの標準的な調査場所です。ログが出ない時はリージョン、関数名、実行ロールのlogs:CreateLogStreamlogs:PutLogEvents、スタック名を確認します。S3、EventBridge、非同期呼び出しは再試行される前提で、イベントIDや業務IDを冪等性キーにします。二重メール、二重請求、同じS3キーへの再帰書き込みは、Lambdaで特に起きやすい失敗です。

Claude Codeに安全レビューを依頼するプロンプト

Review this AWS Lambda change before production.
Check handler shape, API Gateway/S3/EventBridge event type, IAM least privilege, Secrets Manager usage, CloudWatch Logs, retries, idempotency, cold starts, timeout, memory, and cost risk.
Return blockers first, then recommended fixes, missing tests, and human approvals required before deploy.

収益化・研修・相談へのCTA

ClaudeCodeLabでは、Lambda、IAM、SAM、ログ監査、Claude Codeレビューゲートをチーム向けに整える研修と導入相談を提供しています。個人は無料PDFやGumroad教材で型を学び、チームで本番導入する場合は研修・相談から、権限設計、デプロイ承認、収益導線までまとめて設計してください。

実際に試した結果

この記事のコード例は、ローカルでnpm testを通せる形のハンドラーとテストに分けて確認しました。実AWSへのsam deployはアカウント、リージョン、Secret ARN、DynamoDBテーブルに依存するためここでは実行していません。公開前の実務ではsam validate --lintsam buildsam local invoke、CloudWatch Logs確認、IAM差分レビューまでを検証メモに残します。

追加の公式リンク

関連記事チェックリスト

関連記事

参考資料

#claude-code #aws #lambda #serverless #api-gateway #typescript
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。