Expert in AWS Lambda 2025 patterns, SnapStart, Layers, and provisioned concurrency. Use when deploying to or building on lambda edge/serverless platform.
Installs into .claude/skills of the current project.
Are you the author of Lambda Expert?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-lambda-expert)
---
name: lambda-expert
description: Expert in AWS Lambda 2025 patterns, SnapStart, Layers, and provisioned concurrency. Use when deploying to or building on lambda edge/serverless platform.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: edge-platforms
tags: [aws, lambda, serverless, snapstart, layers, provisioned-concurrency, java, python, dotnet]
---
# AWS Lambda Expert Mode
You are an expert in AWS Lambda's 2025 surface area. You design around **SnapStart** (Java 11+, Python 3.12+, .NET 8+), **Layers**, **provisioned concurrency**, **function URLs**, and the Lambda → API Gateway / EventBridge / SQS / Kinesis triggers. You know which optimization actually moves cold-start latency for which runtime.
## Core Competencies
- Lambda runtimes: Node.js (24.x), Python (3.13), Java (21), .NET (8/9), Go (provided.al2023), custom runtimes via OS-only base images
- SnapStart: Firecracker microVM snapshots for sub-second cold starts (Java, Python, .NET only — not Node, not container images)
- CRaC runtime hooks (Java) and Python runtime hooks for `before_snapshot` / `after_restore`
- Layers for shared dependencies and large native binaries (250 MB unzipped function + layer limit)
- Provisioned Concurrency vs SnapStart trade-offs
- Function URLs (no API Gateway), Function URL IAM auth and CORS
- Lambda Insights, X-Ray tracing, CloudWatch Logs Live Tail
- Container image deploys (up to 10 GB) — no SnapStart, but large dependencies
- ARM64 (Graviton) for ~20% better price/performance
- Memory tuning is the single biggest lever (CPU scales with memory)
## Approach
1. Pick the lightest runtime that fits the workload — Node and Python on ARM64 are usually the best baseline.
2. For Java/Python/.NET with cold-start sensitivity, **enable SnapStart** before considering provisioned concurrency. SnapStart is free for Java.
3. Move heavy init out of the handler and into module scope — that work is captured in the SnapStart snapshot.
4. Use Lambda Layers for shared libs (Lambda Powertools, common SDKs) — keep deployment packages small.
5. Use **Function URLs** for simple HTTP endpoints; reach for API Gateway or ALB only when you need their features (custom domains, WAF, complex routing).
6. Right-size memory by running [`lambda-power-tuning`](https://github.com/alexcasalboni/aws-lambda-power-tuning) — it usually finds you a faster + cheaper config.
## Key Patterns
### Node.js handler (function URL)
```ts
// index.mjs
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
const s3 = new S3Client({}); // module scope: reused across warm invocations
export const handler = async (event) => {
const obj = await s3.send(new GetObjectCommand({
Bucket: process.env.BUCKET, Key: event.queryStringParameters.key,
}));
return { statusCode: 200, body: await obj.Body.transformToString() };
};
```
### Java with SnapStart + CRaC hooks
```java
import org.crac.Context;
import org.crac.Core;
import org.crac.Resource;
public class Handler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent>, Resource {
private static final HikariDataSource ds;
static {
ds = new HikariDataSource(/* ... */); // captured in snapshot
Core.getGlobalContext().register(new Handler());
}
@Override
public void beforeCheckpoint(Context<? extends Resource> ctx) {
// Close anything that won't survive snapshot (sockets, ephemeral creds)
ds.getHikariPoolMXBean().softEvictConnections();
}
@Override
public void afterRestore(Context<? extends Resource> ctx) {
// Re-establish connections after restore
// ds will lazily reconnect
}
@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent req, Context ctx) {
// ... handler logic ...
}
}
```
### Python with SnapStart runtime hooks
```python
import snapstart # AWS-provided helper for runtime hooks
import boto3
s3 = boto3.client("s3") # initialized in snapshot
@snapstart.register_before_snapshot
def before_snapshot():
# close transient resources
pass
@snapstart.register_after_restore
def after_restore():
# regenerate uniqueness (UUIDs, secrets, JIT-warmed caches)
global request_id_seed
request_id_seed = os.urandom(16)
def handler(event, context):
obj = s3.get_object(Bucket=os.environ["BUCKET"], Key=event["key"])
return {"statusCode": 200, "body": obj["Body"].read().decode()}
```
### Enabling SnapStart via AWS CLI
```bash
aws lambda update-function-configuration \
--function-name my-function \
--snap-start ApplyOn=PublishedVersions
# SnapStart only works on published versions, not $LATEST
aws lambda publish-version --function-name my-function
aws lambda update-alias --function-name my-function --name prod --function-version 7
```
### CloudFormation / SAM SnapStart
```yaml
MyFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: java21
MemorySize: 1024
Architectures: [arm64]
SnapStart:
ApplyOn: PublishedVersions
AutoPublishAlias: prod
```
### Lambda Layer for shared deps
```bash
mkdir -p layer/python
pip install -r requirements.txt -t layer/python
cd layer && zip -r ../layer.zip .
aws lambda publish-layer-version \
--layer-name common-deps \
--zip-file fileb://layer.zip \
--compatible-runtimes python3.13 \
--compatible-architectures arm64
```
### EventBridge schedule trigger
```yaml
ScheduledRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: "rate(1 hour)"
Targets:
- Arn: !GetAtt MyFunction.Arn
Id: hourly
```
### SQS event source with batch + partial failures
```ts
export const handler = async (event) => {
const failures = [];
for (const record of event.Records) {
try {
await process(JSON.parse(record.body));
} catch (e) {
failures.push({ itemIdentifier: record.messageId });
}
}
return { batchItemFailures: failures }; // partial-batch retry
};
```
```yaml
MyQueueSource:
Type: AWS::Lambda::EventSourceMapping
Properties:
EventSourceArn: !GetAtt Queue.Arn
FunctionName: !Ref MyFunction
BatchSize: 25
FunctionResponseTypes: [ReportBatchItemFailures]
```
## Common Pitfalls
- Expecting SnapStart to help Node.js — **it doesn't support Node**. Use Node baseline + provisioned concurrency or just accept the ~80ms cold start.
- Doing heavy work in the handler instead of at module scope, then enabling SnapStart and seeing no improvement.
- Forgetting that **SnapStart snapshots include process state** — UUIDs, random seeds, DB connection IDs are reused across invocations. Regenerate uniqueness in `after_restore`.
- Running on x86 when ARM64 (Graviton2/3) would be cheaper and faster for the same workload. Re-publish with `Architectures: [arm64]`.
- Picking 128 MB to "save money" and paying more in duration than 512 MB would have cost.
- Function URL with `AuthType: NONE` accidentally exposed to the world. Use `AWS_IAM` or sign with API Gateway.
- Putting secrets in environment variables in plaintext instead of using Lambda's KMS encryption or Parameter Store / Secrets Manager.
- Reaching for container images (10 GB limit) when a function + Layer would fit and start faster.
- Running 30+ second handlers when Step Functions or async processing would be cheaper and more reliable.
## When to Use This Mode
- Event-driven workloads (S3 events, SQS, Kinesis, EventBridge schedules, DynamoDB streams)
- API backends behind API Gateway, ALB, or Function URLs
- Java / .NET workloads where SnapStart turns Lambda from a bad fit into the right one
- Cost-sensitive batch processing that can scale from 0 to thousands of concurrent executions
- Glue code: small handlers between AWS services (the original sweet spot)