serverless-patterns
Serverless patterns: cold start optimization (Provisioned Concurrency, SnapStart, keep-warm), event source mapping (S3/SQS/DynamoDB Streams/EventBridge), AWS Step Functions, Lambda Powertools (logging/metrics/tracing), idempotency, cost model, and observability with X-Ray.
Best use case
serverless-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Serverless patterns: cold start optimization (Provisioned Concurrency, SnapStart, keep-warm), event source mapping (S3/SQS/DynamoDB Streams/EventBridge), AWS Step Functions, Lambda Powertools (logging/metrics/tracing), idempotency, cost model, and observability with X-Ray.
Teams using serverless-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/serverless-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How serverless-patterns Compares
| Feature / Agent | serverless-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Serverless patterns: cold start optimization (Provisioned Concurrency, SnapStart, keep-warm), event source mapping (S3/SQS/DynamoDB Streams/EventBridge), AWS Step Functions, Lambda Powertools (logging/metrics/tracing), idempotency, cost model, and observability with X-Ray.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Serverless Patterns
Production patterns for AWS Lambda and serverless architectures — cold starts, event routing, orchestration, and observability.
## When to Activate
- Diagnosing Lambda cold start latency
- Designing event-driven workflows (S3 → Lambda, SQS batch processing)
- Building Step Functions state machines
- Adding structured logging/tracing with Lambda Powertools
- Calculating serverless cost vs. container cost
- Implementing idempotency for at-least-once delivery
- Choosing between Provisioned Concurrency, SnapStart, or keep-warm pings for a latency-sensitive function
- Debugging partial batch failures in SQS or DynamoDB Streams event source mappings
---
## Cold Start Deep Dive
### What Causes Cold Starts
```
Cold Start = Container Boot + Runtime Init + Function Init
~100-500ms + ~50-200ms + your code
Warm Start = (container already running)
~1-10ms (just your function code)
```
**Cold Start by Runtime (approximate):**
| Runtime | Cold Start |
|---------|-----------|
| Rust (custom runtime) | ~1ms |
| Go | ~5ms |
| Node.js 20 | ~80–150ms |
| Python 3.12 | ~100–300ms |
| Java 21 (without SnapStart) | ~1000–3000ms |
| Java 21 (with SnapStart) | ~100–200ms |
### Mitigation Strategies
**1. Provisioned Concurrency (eliminates cold starts)**
```yaml
# serverless.yml / SAM template
ProvisionedConcurrencyConfig:
ProvisionedConcurrentExecutions: 5 # Always warm instances
# Schedule scaling (cost optimization)
# Scale up before peak, down after
aws application-autoscaling register-scalable-target \
--service-namespace lambda \
--resource-id function:my-function:prod \
--scalable-dimension lambda:function:ProvisionedConcurrency
aws application-autoscaling put-scheduled-action \
--service-namespace lambda \
--resource-id function:my-function:prod \
--scalable-dimension lambda:function:ProvisionedConcurrency \
--scheduled-action-name scale-up-morning \
--schedule "cron(0 7 * * ? *)" \
--scalable-target-action MinCapacity=10,MaxCapacity=10
```
**2. SnapStart (Java only — Firecracker MicroVM snapshot)**
```yaml
# SAM template
MyFunction:
Type: AWS::Serverless::Function
Properties:
SnapStart:
ApplyOn: PublishedVersions
AutoPublishAlias: prod
```
**3. Keep-Warm Pings (free mitigation)**
```typescript
// handler — detect and discard warm pings
export const handler = async (event: any) => {
if (event.source === 'keep-warm') {
return { statusCode: 200 };
}
return handleRealRequest(event);
};
```
```yaml
# EventBridge rule — ping every 5 minutes
KeepWarmRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: rate(5 minutes)
Targets:
- Id: MyLambdaTarget
Arn: !GetAtt MyFunction.Arn
Input: '{"source": "keep-warm"}'
```
**4. Minimize Package Size**
```bash
# Check your Lambda deployment size
aws lambda get-function --function-name my-function \
--query 'Configuration.CodeSize'
# Reduce: only bundle what you need
# Node.js: esbuild with tree-shaking
esbuild src/handler.ts --bundle --minify --target=node20 \
--platform=node --outfile=dist/handler.js
# Python: pip install --no-deps, use Lambda Layers for shared deps
```
**5. Move Initialization Outside Handler**
```typescript
// WRONG: DB connection created on every invocation
export const handler = async (event) => {
const db = new Database(process.env.DB_URL); // ❌ Cold start every time
return db.query('SELECT ...');
};
// CORRECT: Initialize once, reuse across warm invocations
const db = new Database(process.env.DB_URL); // ✅ Runs once per container
export const handler = async (event) => {
return db.query('SELECT ...');
};
```
---
## Event Source Mapping
### S3 → Lambda
```typescript
// S3 event structure
interface S3Event {
Records: Array<{
s3: {
bucket: { name: string };
object: { key: string; size: number; eTag: string };
};
eventName: string; // 'ObjectCreated:Put', 'ObjectRemoved:Delete'
}>;
}
export const handler = async (event: S3Event) => {
for (const record of event.Records) {
const { bucket, object } = record.s3;
const key = decodeURIComponent(object.key.replace(/\+/g, ' '));
const file = await s3.getObject({
Bucket: bucket.name,
Key: key,
}).promise();
await processFile(file.Body as Buffer, key);
}
};
```
### SQS → Lambda (Batch Processing)
```typescript
import { SQSEvent, SQSBatchResponse } from 'aws-lambda';
export const handler = async (event: SQSEvent): Promise<SQSBatchResponse> => {
const failures: SQSBatchResponse['batchItemFailures'] = [];
await Promise.all(
event.Records.map(async (record) => {
try {
const message = JSON.parse(record.body);
await processMessage(message);
} catch (error) {
// Partial batch failure — only failed items go back to queue
failures.push({ itemIdentifier: record.messageId });
}
})
);
return { batchItemFailures: failures };
};
```
```yaml
# SAM/CDK — SQS trigger configuration
MyFunction:
Events:
SQSQueue:
Type: SQS
Properties:
Queue: !GetAtt MyQueue.Arn
BatchSize: 10
FunctionResponseTypes:
- ReportBatchItemFailures # Required for partial failure handling
MaximumBatchingWindowInSeconds: 5
```
### DynamoDB Streams → Lambda (CDC)
```typescript
import { DynamoDBStreamEvent, DynamoDBRecord } from 'aws-lambda';
import { unmarshall } from '@aws-sdk/util-dynamodb';
export const handler = async (event: DynamoDBStreamEvent) => {
for (const record of event.Records) {
const eventType = record.eventName; // 'INSERT' | 'MODIFY' | 'REMOVE'
if (eventType === 'INSERT' || eventType === 'MODIFY') {
const newItem = unmarshall(record.dynamodb?.NewImage ?? {});
await syncToSearchIndex(newItem);
}
if (eventType === 'REMOVE') {
const oldItem = unmarshall(record.dynamodb?.OldImage ?? {});
await removeFromSearchIndex(oldItem.id);
}
}
};
```
### EventBridge → Lambda
```typescript
// EventBridge event
interface OrderPlacedEvent {
source: string; // 'myapp.orders'
'detail-type': string; // 'Order Placed'
detail: {
orderId: string;
customerId: string;
amount: number;
};
}
export const handler = async (event: EventBridge.EventBridgeEvent<'Order Placed', OrderDetail>) => {
const { orderId, customerId, amount } = event.detail;
await processOrder({ orderId, customerId, amount });
};
```
```yaml
# EventBridge rule — content-based filtering
OrderRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source: ['myapp.orders']
detail-type: ['Order Placed']
detail:
amount: [{ numeric: ['>', 100] }] # Only large orders
Targets:
- Id: ProcessLargeOrder
Arn: !GetAtt ProcessOrderFunction.Arn
```
---
## AWS Step Functions
### State Machine Types
| Type | Duration | Pricing | Use Case |
|------|----------|---------|---------|
| Standard | Up to 1 year | Per state transition | Long-running workflows, auditing |
| Express (Async) | Up to 5 minutes | Per invocation + duration | High-volume events |
| Express (Sync) | Up to 5 minutes | Per invocation + duration | Request-response |
### State Types
```json
{
"Comment": "Order processing workflow",
"StartAt": "ValidateOrder",
"States": {
"ValidateOrder": {
"Type": "Task",
"Resource": "arn:aws:lambda:...:function:ValidateOrder",
"Next": "ChargePayment",
"Catch": [{
"ErrorEquals": ["ValidationError"],
"Next": "HandleValidationError"
}],
"Retry": [{
"ErrorEquals": ["States.TaskFailed"],
"IntervalSeconds": 2,
"MaxAttempts": 3,
"BackoffRate": 2.0
}]
},
"ChargePayment": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke.waitForTaskToken",
"Parameters": {
"FunctionName": "ChargePayment",
"Payload": {
"orderId.$": "$.orderId",
"taskToken.$": "$$.Task.Token"
}
},
"HeartbeatSeconds": 300,
"Next": "FulfillOrder"
},
"FulfillOrder": {
"Type": "Parallel",
"Branches": [
{
"StartAt": "ShipItems",
"States": {
"ShipItems": { "Type": "Task", "Resource": "...", "End": true }
}
},
{
"StartAt": "SendConfirmation",
"States": {
"SendConfirmation": { "Type": "Task", "Resource": "...", "End": true }
}
}
],
"Next": "UpdateInventory"
},
"WaitForRestock": {
"Type": "Wait",
"Seconds": 86400,
"Next": "CheckInventory"
},
"OrderComplete": {
"Type": "Succeed"
},
"HandleValidationError": {
"Type": "Fail",
"Error": "ValidationFailed",
"Cause": "Order validation failed"
}
}
}
```
### Map State (Fan-Out)
```json
{
"ProcessItems": {
"Type": "Map",
"ItemsPath": "$.items",
"MaxConcurrency": 10,
"Iterator": {
"StartAt": "ProcessItem",
"States": {
"ProcessItem": {
"Type": "Task",
"Resource": "arn:aws:lambda:...:function:ProcessItem",
"End": true
}
}
},
"Next": "Aggregate"
}
}
```
---
## Lambda Powertools
Unified library for structured logging, metrics, and tracing:
```bash
npm install @aws-lambda-powertools/logger @aws-lambda-powertools/metrics @aws-lambda-powertools/tracer
```
### Logger
```typescript
import { Logger } from '@aws-lambda-powertools/logger';
const logger = new Logger({
serviceName: 'order-service',
logLevel: 'INFO',
});
export const handler = async (event: any) => {
// Automatically adds requestId, function name, cold start flag
logger.info('Processing order', { orderId: event.orderId });
try {
const result = await processOrder(event.orderId);
logger.info('Order processed', { orderId: event.orderId, result });
return result;
} catch (error) {
logger.error('Order processing failed', { error, orderId: event.orderId });
throw error;
}
};
```
### Metrics
```typescript
import { Metrics, MetricUnit } from '@aws-lambda-powertools/metrics';
const metrics = new Metrics({ namespace: 'OrderService', serviceName: 'order-processor' });
export const handler = async (event: any) => {
metrics.addMetric('OrdersReceived', MetricUnit.Count, 1);
const start = Date.now();
await processOrder(event);
metrics.addMetric('ProcessingTime', MetricUnit.Milliseconds, Date.now() - start);
metrics.addMetric('OrdersSucceeded', MetricUnit.Count, 1);
metrics.publishStoredMetrics(); // Flush to CloudWatch
};
```
### Tracer (X-Ray)
```typescript
import { Tracer } from '@aws-lambda-powertools/tracer';
const tracer = new Tracer({ serviceName: 'order-service' });
export const handler = async (event: any) => {
const segment = tracer.getSegment();
const subsegment = segment?.addNewSubsegment('processOrder');
try {
const result = await processOrder(event);
tracer.putAnnotation('orderId', event.orderId);
tracer.putMetadata('result', result);
return result;
} catch (error) {
subsegment?.addError(error as Error);
throw error;
} finally {
subsegment?.close();
}
};
```
---
For idempotency (Lambda Powertools idempotency, DynamoDB persistence), cost model (Lambda vs. Container break-even), and observability (CloudWatch Insights queries), see skill `serverless-patterns-advanced`.
## Reference
- `edge-patterns` — Cloudflare Workers, Vercel Edge Middleware (CPU-constrained, no cold starts)
- `observability` — General observability patterns (OpenTelemetry, Grafana)
- `chaos-engineering` — Testing Lambda failure modes (throttling, DLQ exhaustion)Related Skills
zero-trust-patterns
Zero-Trust security patterns — mTLS between microservices (Istio/SPIFFE), SPIRE workload identity, OPA/Envoy authorization, NetworkPolicy default-deny-all, short-lived credentials, service mesh security, and Kubernetes RBAC hardening.
webrtc-patterns
WebRTC patterns — peer connection setup, ICE/STUN/TURN configuration, signaling server design, SFU vs mesh topology, screen sharing, media track management, and reconnect/ICE restart handling.
webhook-patterns
Webhook patterns for receiving, verifying (HMAC), and idempotently processing third-party events. Covers Stripe, GitHub, and generic webhook patterns, delivery guarantees, retry handling, and testing.
wasm-patterns
WebAssembly patterns: wasm-pack, wasm-bindgen (JS↔Wasm interop), WASI, Component Model, wasm-opt, Rust-to-WASM compilation, JS integration (web workers, streaming instantiation), and production deployment (CDN, Content-Type headers).
ux-micro-patterns
UX micro-patterns for every product state: Empty States, Loading States (skeleton screens, spinners, optimistic UI), Error States, Success States, Confirmation Dialogs, Onboarding Flows, and Progressive Disclosure. These patterns apply to every feature — done wrong, they're the biggest source of user confusion.
typescript-patterns
TypeScript patterns — type system best practices, strict mode, utility types, generics, discriminated unions, error handling with Result types, and module organization. Core patterns for production TypeScript.
typescript-patterns-advanced
Advanced TypeScript — mapped types, template literal types, conditional types, infer, type guards, decorators, async patterns, testing with Vitest/Jest, and performance. Extends typescript-patterns.
typescript-monorepo-patterns
TypeScript monorepo patterns with Turborepo + pnpm workspaces. Covers package structure, shared configs, task pipeline caching, build orchestration, and publishing strategy.
terraform-patterns
Infrastructure as Code with Terraform — project structure, remote state, modules, workspace strategy, AWS/GCP patterns, CI/CD integration, and security hardening. The standard for managing production infrastructure.
swiftui-patterns
SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS/macOS UI best practices.
swift-patterns
Core Swift patterns — value vs reference types, protocols, generics, optionals, Result, error handling, Codable, and module organization. Foundation for all Swift development.
swift-patterns-advanced
Advanced Swift patterns — property wrappers, result builders, Combine basics, opaque & existential types, macro system, advanced generics, and performance optimization. Extends swift-patterns.