Lambda

Deploy serverless APIs and backend functions on AWS Lambda with API Gateway as the public HTTP endpoint. Scales to zero when idle — pay only for what you use.

Supported Frameworks

AWS Resources

ResourcePurpose
Lambda FunctionRuns your server code
API Gateway HTTP APIPublic HTTP endpoint, routes all traffic to Lambda
CloudWatch LogsFunction logs, retained for 1 month
ACM CertificateSSL for custom domain (optional)
Route53DNS A + AAAA records (optional)

Serverless API Architecture

Users
Route 53
API Gateway
Lambda

Route 53 handles DNS resolution for custom domains. API Gateway manages HTTP requests, authentication, and routing. Lambda executes serverless functions with automatic scaling and pay-per-request pricing.

Quick Start

Installation

Terminal window
bun add -D @thunder-so/thunder

Configuration

stack/prod.ts
import { Cdk, Lambda, type LambdaProps } from '@thunder-so/thunder';
const config: LambdaProps = {
env: {
account: 'YOUR_ACCOUNT_ID',
region: 'us-east-1',
},
application: 'myapp',
service: 'api',
environment: 'prod',
rootDir: '.',
functionProps: {
runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X,
architecture: Cdk.aws_lambda.Architecture.ARM_64,
codeDir: 'dist',
handler: 'index.handler',
memorySize: 512,
timeout: 10,
},
};
new Lambda(
new Cdk.App(),
`${config.application}-${config.service}-${config.environment}-stack`,
config
);

Deploy

Terminal window
bun run build
npx cdk deploy --app "bunx tsx stack/prod.ts" --profile default

CDK outputs the API Gateway URL:

Outputs:
myapp-api-prod-stack.ApiGatewayUrl = https://abc123.execute-api.us-east-1.amazonaws.com

Custom Domain

Connect your API to a custom domain. The certificate must be issued in the same region as your Lambda function — unlike Static, Lambda uses a regional (not global) certificate.

stack/prod.ts
const config: LambdaProps = {
// ...
domain: 'api.example.com',
hostedZoneId: 'Z1D633PJN98FT9',
regionalCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/abc-123',
};

Advanced Configuration

Performance and Concurrency

Fine-tune your function’s performance with memory, timeout, and concurrency settings. Memory also controls proportional CPU allocation.

stack/prod.ts
const config: LambdaProps = {
// ...
functionProps: {
runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X,
architecture: Cdk.aws_lambda.Architecture.ARM_64,
memorySize: 1792, // more memory = more CPU
timeout: 10,
tracing: true, // enable AWS X-Ray
keepWarm: true, // ping every 5 min to prevent cold starts
reservedConcurrency: 10, // hard cap on simultaneous executions
provisionedConcurrency: 2, // pre-warmed instances, eliminates cold starts
url: true, // also expose a direct Lambda Function URL
},
};

Environment Variables and Secrets

stack/prod.ts
const config: LambdaProps = {
// ...
functionProps: {
variables: [
{ NODE_ENV: 'production' },
{ API_URL: 'https://api.example.com' },
],
secrets: [
{
key: 'DATABASE_URL',
resource: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:/myapp/DATABASE_URL-abc123',
},
],
},
};

Thunder automatically grants the Lambda execution role secretsmanager:GetSecretValue on each referenced secret.

Container Deployments

Deploy Lambda functions as container images to use custom runtimes, package large dependencies, or exceed the 250 MB zip limit. Container images support up to 10 GB.

Node.js Container

Dockerfile
FROM public.ecr.aws/lambda/nodejs:22 AS builder
WORKDIR ${LAMBDA_TASK_ROOT}
COPY . .
RUN npm ci
RUN npm run build
FROM public.ecr.aws/lambda/nodejs:22
WORKDIR ${LAMBDA_TASK_ROOT}
COPY --from=builder /var/task/dist/* ./
COPY --from=builder /var/task/node_modules ./node_modules
CMD ["index.handler"]
stack/prod.ts
const config: LambdaProps = {
// ...
functionProps: {
dockerFile: 'Dockerfile',
memorySize: 1792,
keepWarm: true,
},
};

Bun Runtime Container

Bun is not a managed Lambda runtime, so it runs as a container. The bootstrap binary handles the Lambda runtime protocol and forwards requests to your Bun fetch handler.

Dockerfile.bun
# Stage 1: Build the Bun Lambda bootstrap
FROM oven/bun:latest AS bun
WORKDIR /tmp
RUN apt-get update && apt-get install -y curl
RUN curl -fsSL https://raw.githubusercontent.com/oven-sh/bun/main/packages/bun-lambda/runtime.ts -o runtime.ts
RUN bun install aws4fetch
RUN bun build --compile runtime.ts --outfile bootstrap
# Stage 2: Build your app
FROM oven/bun:latest AS builder
WORKDIR /tmp
COPY . .
RUN bun install
RUN bun run build
# Stage 3: Runtime image
FROM public.ecr.aws/lambda/provided:al2023
WORKDIR ${LAMBDA_TASK_ROOT}
COPY --from=bun /tmp/bootstrap ${LAMBDA_RUNTIME_DIR}
COPY --from=builder /tmp/dist/ ./
COPY --from=builder /tmp/node_modules ./node_modules
CMD ["lambda-bun.fetch"]
stack/prod.ts
const config: LambdaProps = {
// ...
functionProps: {
dockerFile: 'Dockerfile.bun',
memorySize: 512,
keepWarm: true,
},
};

CI/CD Pipeline

Zip Deployment Pipeline

GitHub
CodePipeline
CodeBuild
Lambda

GitHub triggers deployments on code changes. CodePipeline orchestrates the workflow while CodeBuild packages the function code into a zip file and deploys directly to Lambda.

stack/prod.ts
const config: LambdaProps = {
// ...
accessTokenSecretArn: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:github-token-XXXXXX',
sourceProps: {
owner: 'your-username',
repo: 'your-repo',
branchOrRef: 'main',
},
buildProps: {
runtime: 'nodejs',
runtime_version: '22',
installcmd: 'bun install',
buildcmd: 'bun run build',
outputDir: 'dist',
},
};

Container Deployment Pipeline

GitHub
CodePipeline
CodeBuild
ECR
Lambda

GitHub triggers deployments. CodeBuild builds Docker images with custom runtimes, pushes to ECR, then deploys container images to Lambda for advanced use cases requiring custom dependencies or alternative runtimes like Bun.

stack/prod.ts
const config: LambdaProps = {
// ...
accessTokenSecretArn: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:github-token-XXXXXX',
sourceProps: {
owner: 'your-username',
repo: 'your-repo',
branchOrRef: 'main',
},
functionProps: {
dockerFile: 'Dockerfile',
},
buildProps: {
installcmd: 'bun install',
buildcmd: 'bun run build',
},
};

Stack Outputs

OutputDescription
ApiGatewayUrlAPI Gateway endpoint URL
LambdaFunctionLambda function name
LambdaFunctionUrlDirect Lambda URL (only if url: true)
Route53DomainCustom domain URL (only if domain is configured)

Destroy

Terminal window
npx cdk destroy --app "bunx tsx stack/prod.ts" --profile default