← Blog

Claude API AWS Lambda Deployment Tutorial

2026-10-24 · 5 min read · SubToAPI Team

Deploying the Claude API on AWS Lambda means wrapping your Anthropic (or compatible) API calls inside a Lambda function handler, exposing it through API Gateway or a Lambda Function URL, and managing the specific constraints Lambda imposes — execution timeouts, cold starts, and the fact that Lambda doesn't natively support long-lived streaming connections the way a persistent server does.

This tutorial walks through a working deployment: project structure, the handler code, IAM permissions, environment variable handling for your API key, and the tradeoffs you need to know before you put Claude behind Lambda in production.

Why deploy Claude on Lambda

Lambda is a reasonable choice when you want a Claude-powered endpoint that scales to zero, costs nothing when idle, and doesn't require you to manage a server. It fits well for:

It fits poorly for:

If you just need an HTTPS endpoint with streaming, tool use, and usage metadata without writing and maintaining Lambda glue code, a hosted gateway like SubToAPI gives you that directly — more on that at the end.

Project structure

claude-lambda/
├── index.js
├── package.json
└── node_modules/

Install the Anthropic SDK (or use fetch directly, which avoids bundling the SDK):

npm install @anthropic-ai/sdk

Handler code

// index.js
const Anthropic = require("@anthropic-ai/sdk");

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

exports.handler = async (event) => {
  try {
    const body = JSON.parse(event.body || "{}");
    const prompt = body.prompt;

    if (!prompt) {
      return {
        statusCode: 400,
        body: JSON.stringify({ error: "prompt is required" }),
      };
    }

    const response = await client.messages.create({
      model: "claude-sonnet-4-20250514",
      max_tokens: 1024,
      messages: [{ role: "user", content: prompt }],
    });

    return {
      statusCode: 200,
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ text: response.content[0].text }),
    };
  } catch (err) {
    console.error(err);
    return {
      statusCode: 500,
      body: JSON.stringify({ error: "internal error" }),
    };
  }
};

Package it:

zip -r function.zip index.js node_modules package.json

Deploying with the AWS CLI

aws lambda create-function \
  --function-name claude-api-handler \
  --runtime nodejs20.x \
  --role arn:aws:iam::<account-id>:role/claude-lambda-role \
  --handler index.handler \
  --zip-file fileb://function.zip \
  --timeout 30 \
  --memory-size 512

Set the API key as an environment variable rather than hardcoding it:

aws lambda update-function-configuration \
  --function-name claude-api-handler \
  --environment "Variables={ANTHROPIC_API_KEY=sk-ant-...}"

For anything beyond a personal test, use AWS Secrets Manager or SSM Parameter Store instead of a plain environment variable, and grant the Lambda execution role secretsmanager:GetSecretValue scoped to that one secret.

IAM role requirements

The execution role needs the standard Lambda basic execution policy plus, if you're pulling the key from Secrets Manager, a scoped read permission:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "secretsmanager:GetSecretValue",
      "Resource": "arn:aws:secretsmanager:region:account-id:secret:claude-api-key-*"
    }
  ]
}

Avoid using * on the Resource field in production — scope it to the exact secret ARN.

Exposing it via API Gateway

Create an HTTP API (cheaper and faster than REST API Gateway for this use case):

aws apigatewayv2 create-api \
  --name claude-api \
  --protocol-type HTTP \
  --target arn:aws:lambda:region:account-id:function:claude-api-handler

Add a Lambda permission so API Gateway can invoke it:

aws lambda add-permission \
  --function-name claude-api-handler \
  --statement-id apigateway-invoke \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:region:account-id:*/*"

Timeout, cold starts, and streaming caveats

A few Lambda-specific constraints matter for Claude workloads:

When Lambda adds more complexity than value

If your actual requirement is "a stable HTTPS endpoint that calls Claude, streams responses, supports tool use, and gives me usage metadata per API key" — that's a lot of plumbing to build and maintain on Lambda: streaming response modes, IAM policies, Secrets Manager rotation, per-key rate limiting, and dashboards for usage.

SubToAPI turns your existing Claude access into that endpoint directly: issue scoped sub_live_... application keys, call /v1/messages with standard streaming and tool use support, and see usage per key in one dashboard — no Lambda, no IAM, no Secrets Manager setup. Check the quickstart or the streaming docs to see the request shape, and the tools docs if you need function calling without building the orchestration yourself. Plans start with a free trial at signup, with pricing from Solo at €9 up through Team and Scale tiers — details on /pricing.

How do I keep my Anthropic API key secure in a Lambda deployment?

Store it in AWS Secrets Manager or SSM Parameter Store, not as a plain environment variable in version-controlled infrastructure code. Scope the Lambda execution role's IAM permission to the exact secret ARN, and rotate the key periodically.

Can Lambda stream Claude's token-by-token responses to the client?

Not through standard API Gateway proxy integrations, which buffer the full response. Lambda Function URLs with response streaming invoke mode support it, but with more setup than a direct persistent-server or managed-gateway approach.

What Lambda timeout should I set for Claude API calls?

30 to 60 seconds covers most single-request completions. For longer generations or multi-step tool-use chains, consider breaking the work into async steps with SQS or Step Functions rather than relying on one long-running invocation.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →