name: aws-skills description: AWS development with CDK patterns, serverless architecture, Lambda, API Gateway, DynamoDB, S3, and infrastructure best practices. Use when building or deploying to AWS.
AWS Development Skills
When to Use This Skill
- Building serverless applications on AWS
- Writing AWS CDK infrastructure code
- Configuring Lambda, API Gateway, DynamoDB, S3
- Setting up CI/CD pipelines with AWS
- Optimizing AWS costs and performance
AWS CDK Patterns
Project Structure
my-service/
├── bin/
│ └── app.ts # CDK app entry point
├── lib/
│ ├── stacks/ # Stack definitions
│ │ ├── api-stack.ts
│ │ └── database-stack.ts
│ └── constructs/ # Reusable constructs
├── lambda/ # Lambda function code
│ └── handlers/
├── test/ # Tests
└── cdk.json
Stack Pattern
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';
export class ApiStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Lambda function
const handler = new lambda.Function(this, 'Handler', {
runtime: lambda.Runtime.NODEJS_20_X,
code: lambda.Code.fromAsset('lambda'),
handler: 'index.handler',
memorySize: 256,
timeout: cdk.Duration.seconds(30),
environment: {
NODE_ENV: 'production',
},
});
// API Gateway
const api = new apigateway.RestApi(this, 'Api', {
restApiName: 'My Service',
deployOptions: {
stageName: 'prod',
},
});
api.root.addMethod('GET', new apigateway.LambdaIntegration(handler));
}
}
Lambda Best Practices
Handler Pattern
// lambda/handlers/api.ts
import { APIGatewayProxyHandler } from 'aws-lambda';
// Initialize outside handler for connection reuse
const db = initDatabase();
export const handler: APIGatewayProxyHandler = async (event) => {
try {
const body = JSON.parse(event.body || '{}');
const result = await processRequest(body);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify(result),
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: 'Internal Server Error' }),
};
}
};
Performance Optimization
// Use provisioned concurrency for critical paths
const fn = new lambda.Function(this, 'CriticalFn', {
// ... config
});
const version = fn.currentVersion;
const alias = new lambda.Alias(this, 'ProdAlias', {
aliasName: 'prod',
version,
provisionedConcurrentExecutions: 5,
});
Cold Start Reduction:
- Keep deployment package small
- Use layers for dependencies
- Initialize connections outside handler
- Use ARM64 architecture (Graviton2)
DynamoDB Patterns
Single-Table Design
// Table with GSI for access patterns
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,
});
table.addGlobalSecondaryIndex({
indexName: 'GSI1',
partitionKey: { name: 'GSI1PK', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'GSI1SK', type: dynamodb.AttributeType.STRING },
});
Access Patterns
// User by ID: PK=USER#123, SK=PROFILE
// User orders: PK=USER#123, SK=ORDER#timestamp
// Order by ID: GSI1PK=ORDER#456, GSI1SK=ORDER#456
const params = {
TableName: 'MyTable',
KeyConditionExpression: 'PK = :pk AND begins_with(SK, :sk)',
ExpressionAttributeValues: {
':pk': 'USER#123',
':sk': 'ORDER#',
},
};
S3 Best Practices
const bucket = new s3.Bucket(this, 'Bucket', {
encryption: s3.BucketEncryption.S3_MANAGED,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
versioned: true,
lifecycleRules: [
{
transitions: [
{
storageClass: s3.StorageClass.INTELLIGENT_TIERING,
transitionAfter: cdk.Duration.days(30),
},
],
},
],
});
API Gateway Patterns
REST API with Validation
const api = new apigateway.RestApi(this, 'Api', {
restApiName: 'Service',
deployOptions: {
throttlingRateLimit: 1000,
throttlingBurstLimit: 2000,
},
});
// Request validation
const model = api.addModel('CreateItemModel', {
contentType: 'application/json',
schema: {
type: apigateway.JsonSchemaType.OBJECT,
required: ['name'],
properties: {
name: { type: apigateway.JsonSchemaType.STRING },
price: { type: apigateway.JsonSchemaType.NUMBER },
},
},
});
const items = api.root.addResource('items');
items.addMethod('POST', integration, {
requestModels: { 'application/json': model },
requestValidatorOptions: {
validateRequestBody: true,
},
});
IAM Best Practices
// Least privilege
handler.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['dynamodb:GetItem', 'dynamodb:PutItem'],
resources: [table.tableArn],
conditions: {
'ForAllValues:StringEquals': {
'dynamodb:LeadingKeys': ['${aws:userid}'],
},
},
}));
Cost Optimization
| Service | Optimization |
|---|---|
| Lambda | Right-size memory, use Graviton2 |
| DynamoDB | On-demand for variable, provisioned for steady |
| S3 | Intelligent tiering, lifecycle rules |
| API Gateway | Use HTTP APIs when possible (cheaper) |
| CloudWatch | Set log retention periods |
Security Checklist
- Encryption at rest enabled
- Encryption in transit (HTTPS only)
- VPC for sensitive workloads
- Secrets in Secrets Manager (not env vars)
- IAM roles with least privilege
- CloudTrail enabled
- GuardDuty enabled
- Regular security assessments