home / skills / bbeierle12 / skill-mcp-claude / aws-skills
This skill helps you design and deploy scalable AWS infrastructure using CDK patterns, serverless architectures, and cost-aware security with best practices.
npx playbooks add skill bbeierle12/skill-mcp-claude --skill aws-skillsReview the files below or copy the command above to add this skill to your agents.
---
name: aws-skills
description: AWS development with CDK best practices, serverless patterns, cost optimization, and event-driven architecture. Use when deploying to AWS, writing Lambda functions, configuring API Gateway, working with DynamoDB, S3, or any AWS service.
---
# AWS Development Skills
## AWS CDK Best Practices
### Project Structure
```
infrastructure/
├── bin/
│ └── app.ts # CDK app entry point
├── lib/
│ ├── stacks/
│ │ ├── api-stack.ts
│ │ ├── database-stack.ts
│ │ └── storage-stack.ts
│ ├── constructs/
│ │ ├── lambda-function.ts
│ │ └── api-gateway.ts
│ └── config/
│ └── environment.ts
├── lambda/
│ └── handlers/
├── cdk.json
└── package.json
```
### Stack Definition
```typescript
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import { Construct } from 'constructs';
interface ApiStackProps extends cdk.StackProps {
environment: string;
domainName?: string;
}
export class ApiStack extends cdk.Stack {
public readonly api: apigateway.RestApi;
constructor(scope: Construct, id: string, props: ApiStackProps) {
super(scope, id, props);
const handler = new lambda.Function(this, 'ApiHandler', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda/handlers'),
environment: { NODE_ENV: props.environment },
memorySize: 256,
timeout: cdk.Duration.seconds(30),
});
this.api = new apigateway.RestApi(this, 'Api', {
restApiName: `${props.environment}-api`,
deployOptions: {
stageName: props.environment,
throttlingRateLimit: 1000,
throttlingBurstLimit: 500,
},
});
const integration = new apigateway.LambdaIntegration(handler);
this.api.root.addMethod('GET', integration);
}
}
```
## Serverless Patterns
### Lambda Best Practices
```typescript
import { APIGatewayProxyHandler } from 'aws-lambda';
// Initialize outside handler for connection reuse
const dynamodb = new DynamoDB.DocumentClient();
export const handler: APIGatewayProxyHandler = async (event) => {
try {
const body = JSON.parse(event.body || '{}');
const result = await processRequest(body);
return response(200, result);
} catch (error) {
console.error('Error:', error);
return response(500, { error: 'Internal server error' });
}
};
function response(statusCode: number, body: any) {
return {
statusCode,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify(body),
};
}
```
### DynamoDB Single-Table Design
```typescript
const table = new dynamodb.Table(this, 'Table', {
partitionKey: { name: 'PK', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'SK', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});
// Access patterns
// User by ID: PK=USER#123, SK=PROFILE
// User's orders: PK=USER#123, SK=ORDER#timestamp
// Order by ID: GSI1PK=ORDER#456, GSI1SK=ORDER#456
```
### Event-Driven with EventBridge
```typescript
const rule = new events.Rule(this, 'OrderCreatedRule', {
eventPattern: {
source: ['orders'],
detailType: ['OrderCreated'],
},
});
rule.addTarget(new targets.LambdaFunction(processOrderHandler));
rule.addTarget(new targets.SqsQueue(notificationQueue));
```
### SQS + Lambda Pattern
```typescript
const dlq = new sqs.Queue(this, 'DeadLetterQueue');
const queue = new sqs.Queue(this, 'ProcessingQueue', {
visibilityTimeout: cdk.Duration.seconds(300),
deadLetterQueue: { queue: dlq, maxReceiveCount: 3 },
});
processor.addEventSource(new SqsEventSource(queue, {
batchSize: 10,
maxBatchingWindow: cdk.Duration.seconds(5),
}));
```
## Cost Optimization
### Lambda Optimization
```typescript
const handler = new lambda.Function(this, 'Handler', {
memorySize: 256,
timeout: cdk.Duration.seconds(10),
architecture: lambda.Architecture.ARM_64, // Cost savings
});
```
### S3 Lifecycle Rules
```typescript
const bucket = new s3.Bucket(this, 'Bucket', {
lifecycleRules: [{
transitions: [
{ storageClass: s3.StorageClass.INFREQUENT_ACCESS, transitionAfter: cdk.Duration.days(30) },
{ storageClass: s3.StorageClass.GLACIER, transitionAfter: cdk.Duration.days(90) },
],
expiration: cdk.Duration.days(365),
}],
});
```
## Security Best Practices
### IAM Least Privilege
```typescript
// Grant methods (preferred)
table.grantReadWriteData(handler);
bucket.grantRead(handler);
```
### Secrets Management
```typescript
const secret = secretsmanager.Secret.fromSecretNameV2(this, 'DbSecret', 'prod/db/credentials');
secret.grantRead(handler);
```
## Monitoring
### CloudWatch Alarms
```typescript
new cloudwatch.Alarm(this, 'LambdaErrors', {
metric: handler.metricErrors(),
threshold: 1,
evaluationPeriods: 1,
});
```
### X-Ray Tracing
```typescript
const handler = new lambda.Function(this, 'Handler', {
tracing: lambda.Tracing.ACTIVE,
});
```
This skill captures practical AWS development patterns using the CDK, serverless best practices, cost optimization tactics, and event-driven architecture patterns. It focuses on deployable project structure, Lambda and DynamoDB patterns, SQS/EventBridge integrations, security, and monitoring recommendations. Use it as a concise guide when building and operating AWS workloads with JavaScript/TypeScript CDK stacks.
The skill describes a recommended CDK project layout and provides sample stack and construct patterns for API Gateway, Lambda, DynamoDB, S3, SQS, and EventBridge. It explains runtime considerations such as Lambda initialization for connection reuse, single-table DynamoDB access patterns, dead-letter queue handling, lifecycle transitions for S3, and tracing/alarms for observability. It also highlights IAM least-privilege and secrets access patterns to reduce blast radius.
How do I reduce Lambda costs while keeping performance?
Right-size memory and timeout, prefer ARM64 architecture when compatible, and keep cold-starts low by minimizing bundle size and reusing connections initialized outside the handler.
When should I choose single-table DynamoDB?
Choose it when you can define clear access patterns that share a partition key structure; it reduces joins and scales well but requires careful key design and GSIs for alternate queries.