← Blog

Claude API AWS Lambda Deployment Guide

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

Deploying the Claude API on AWS Lambda means packaging your API calls inside a serverless function that runs on demand, scales automatically, and only bills you for execution time. This guide walks through the full setup: writing the handler, managing secrets, handling Lambda's execution limits, and avoiding the most common failure modes developers hit when they move a working local Claude integration into a serverless environment.

The short version: you write a Node.js or Python handler that calls the Claude API, store your API key in AWS Secrets Manager or environment variables, set a timeout well above your expected response time, and put API Gateway or a Lambda Function URL in front of it. The tricky parts are streaming (Lambda doesn't support it well), cold starts, and keeping secrets out of your deployment package. We'll cover all three.

Setting Up the Lambda Function

Start with a basic Node.js handler. Lambda's default runtime handles this cleanly without extra dependencies beyond a fetch-capable Node version (18.x or later ships with native fetch).

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

  const response = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "x-api-key": process.env.CLAUDE_API_KEY,
      "anthropic-version": "2023-06-01",
      "content-type": "application/json",
    },
    body: JSON.stringify({
      model: "claude-sonnet-4-5",
      max_tokens: 1024,
      messages: [{ role: "user", content: body.prompt }],
    }),
  });

  const data = await response.json();

  return {
    statusCode: 200,
    body: JSON.stringify(data),
  };
};

Package this with your dependencies in a zip file, or use a container image if you need more control over the runtime. For most Claude integrations, a plain zip deployment is sufficient since there's no heavy SDK to bundle if you're calling the HTTP API directly.

Managing API Keys Securely

Never hardcode the API key in your handler or commit it to your deployment package. Two solid options:

let cachedKey;

async function getApiKey() {
  if (cachedKey) return cachedKey;
  const client = new SecretsManagerClient();
  const secret = await client.send(
    new GetSecretValueCommand({ SecretId: "claude-api-key" })
  );
  cachedKey = secret.SecretString;
  return cachedKey;
}

Caching outside the handler function body is the key trick here — Lambda reuses the execution context across invocations when traffic is steady, so you avoid refetching the secret on every request.

Handling Timeouts and Cold Starts

Lambda's default timeout is 3 seconds, which is far too short for a Claude completion, especially with longer max_tokens values or extended thinking. Set your function timeout to at least 60 seconds for typical use, and up to 15 minutes (Lambda's hard ceiling) if you're generating very long outputs synchronously.

Cold starts add latency, usually 200–800ms for Node.js runtimes, before your code even runs. If your application is latency-sensitive, consider:

The Streaming Problem

This is the part that trips up most teams. Claude's streaming responses use server-sent events, and standard Lambda invocations (through API Gateway REST or HTTP APIs) buffer the entire response before returning it — you lose the token-by-token experience entirely.

AWS added Lambda response streaming via Function URLs with InvokeMode: RESPONSE_STREAM, which does support chunked responses. It works, but it only applies to direct Function URL invocations, not API Gateway, and it adds configuration complexity (CORS headers have to be set manually on the stream, buffering behavior differs between Node.js versions).

If streaming responses to end users is a requirement and you don't want to manage Lambda's streaming quirks, routing those calls through a platform built for this is often simpler. SubToAPI exposes Claude through a standard HTTPS API with proper SSE streaming support (see /docs/streaming) and application-level API keys (sub_live_...), so your Lambda function can stay a thin, stateless wrapper instead of owning the streaming logic itself. Lambda calls SubToAPI's /v1/messages endpoint, and your frontend or gateway handles the stream the normal way.

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "stream": true,
    "messages": [{"role": "user", "content": "Summarize this ticket"}]
  }'

This also decouples your deployment from direct Anthropic key management — useful if multiple Lambda functions or services across your team need to call Claude and you want centralized usage metadata instead of reconstructing it yourself. Check /pricing if you want to compare the cost of running this centrally versus per-function key management, and /docs/quickstart for the setup steps.

Wiring Up API Gateway

For non-streaming use cases, API Gateway HTTP API (not REST API — it's cheaper and has lower latency overhead) is the standard front door:

  1. Create an HTTP API in API Gateway.
  2. Add a route (e.g., POST /chat) pointing to your Lambda function as the integration target.
  3. Enable CORS if calling from a browser.
  4. Deploy and grab the invoke URL.
aws apigatewayv2 create-api \
  --name claude-proxy \
  --protocol-type HTTP \
  --target arn:aws:lambda:us-east-1:123456789012:function:claude-handler

Set a reasonable throttle (burst and rate limits) on the API Gateway stage to protect against runaway costs if a client retries aggressively on failure.

Cost and IAM Notes

Lambda execution cost is driven by duration and memory allocation — Claude API calls are mostly I/O wait, so allocate just enough memory (256–512MB is usually plenty) rather than over-provisioning. Your IAM execution role needs, at minimum, secretsmanager:GetSecretValue scoped to the specific secret ARN, plus the standard CloudWatch Logs permissions Lambda generates by default. Avoid wildcard resource permissions even for a quick prototype — scope them down before anything touches production traffic.

Questions

Can Lambda handle long-running Claude requests without timing out? Yes, up to Lambda's 15-minute maximum timeout. Set the function timeout explicitly — the 3-second default will fail almost every real Claude request.

Does API Gateway support streaming Claude responses? No. API Gateway buffers the full response. Use a Lambda Function URL with response streaming enabled, or route through an API designed for SSE like SubToAPI's /docs/streaming.

Should I call the Claude API directly from Lambda or through a proxy? Direct calls work fine for simple, low-volume use cases. A proxy becomes valuable once you need centralized key rotation, per-team usage tracking, or streaming support across multiple functions without reimplementing it each time.

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 →