# 3007 Serverless Deployment 7a94e770

> Serverless Deployment Reference

- Skill: `tools-only/3007-serverless-deployment-7a94e770` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/3007-serverless-deployment-7a94e770`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/3007-serverless-deployment-7a94e770/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/tools-only/3007-serverless-deployment-7a94e770

---

# Serverless Deployment Reference

Complete guide for deploying Java Lambda functions with Serverless Framework, AWS SAM, and CI/CD pipelines.

## Table of Contents

1. [Serverless Framework](#serverless-framework)
2. [AWS SAM](#aws-sam)
3. [CI/CD Pipeline](#cicd-pipeline)
4. [Provisioned Concurrency](#provisioned-concurrency)
5. [Monitoring](#monitoring)
6. [Build Optimization](#build-optimization)
7. [Package Optimization](#package-optimization)
8. [Performance Tuning](#performance-tuning)
9. [Rollback Strategy](#rollback-strategy)
10. [Security Best Practices](#security-best-practices)
11. [Cost Optimization](#cost-optimization)
12. [SAM vs Serverless Framework](#sam-vs-serverless-framework)

---

## Serverless Framework

### Basic Configuration

```yaml
service: java-lambda-api

provider:
  name: aws
  runtime: java21
  memorySize: 512
  timeout: 10
  region: ${opt:region, 'us-east-1'}
  stage: ${opt:stage, 'dev'}

  environment:
    STAGE: ${self:provider.stage}
    USERS_TABLE: !Ref UsersTable

  iam:
    role:
      statements:
        - Effect: Allow
          Action:
            - logs:CreateLogGroup
            - logs:CreateLogStream
            - logs:PutLogEvents
          Resource: '*'
        - Effect: Allow
          Action:
            - dynamodb:GetItem
            - dynamodb:PutItem
            - dynamodb:DeleteItem
            - dynamodb:Scan
            - dynamodb:Query
          Resource: !GetAtt UsersTable.Arn

package:
  artifact: build/libs/${self:service}-${self:provider.stage}.jar

functions:
  api:
    handler: com.example.Handler
    events:
      - http:
          path: /{proxy+}
          method: ANY
          cors: true
      - http:
          path: /
          method: ANY
          cors: true

resources:
  Resources:
    UsersTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${self:service}-users-${self:provider.stage}
        BillingMode: PAY_PER_REQUEST
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH

  Outputs:
    ApiUrl:
      Value: !Join ['', ['https://', !Ref ApiGatewayRestApi, '.execute-api.', !Ref 'AWS::Region', '.amazonaws.com/', ${self:provider.stage}]]
      Export:
        Name: ${self:service}-api-url-${self:provider.stage}
```

### Multi-Stage Configuration

```yaml
service: java-lambda-api

provider:
  name: aws
  runtime: java21
  memorySize: ${self:custom.memorySize.${self:provider.stage}}
  timeout: ${self:custom.timeout.${self:provider.stage}}
  region: ${opt:region, 'us-east-1'}
  stage: ${opt:stage, 'dev'}

  environment:
    STAGE: ${self:provider.stage}
    LOG_LEVEL: ${self:custom.logLevel.${self:provider.stage}}

custom:
  memorySize:
    dev: 512
    staging: 1024
    prod: 2048

  timeout:
    dev: 10
    staging: 15
    prod: 30

  logLevel:
    dev: DEBUG
    staging: INFO
    prod: WARN
```

### VPC Configuration

```yaml
provider:
  name: aws
  runtime: java21
  vpc:
    securityGroupIds:
      - !Ref LambdaSecurityGroup
    subnetIds:
      - !Ref PrivateSubnet1
      - !Ref PrivateSubnet2

resources:
  Resources:
    LambdaSecurityGroup:
      Type: AWS::EC2::SecurityGroup
      Properties:
        GroupDescription: Lambda Security Group
        VpcId: !Ref VPC
        SecurityGroupEgress:
          - IpProtocol: tcp
            FromPort: 443
            ToPort: 443
            CidrIp: 0.0.0.0/0

    PrivateSubnet1:
      Type: AWS::EC2::Subnet
      Properties:
        VpcId: !Ref VPC
        CidrBlock: 10.0.1.0/24
        AvailabilityZone: !Select [0, !GetAZs '']

    PrivateSubnet2:
      Type: AWS::EC2::Subnet
      Properties:
        VpcId: !Ref VPC
        CidrBlock: 10.0.2.0/24
        AvailabilityZone: !Select [1, !GetAZs '']
```

### Custom Domain

```yaml
plugins:
  - serverless-domain-manager

custom:
  customDomain:
    domainName: api.example.com
    stage: ${self:provider.stage}
    createRoute53Record: true
    certificateName: '*.example.com'
    endpointType: 'regional'
    securityPolicy: tls_1_2
```

---

## AWS SAM

### Basic Template

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Java Lambda API with SAM

Globals:
  Function:
    Timeout: 10
    MemorySize: 512
    Runtime: java21
    Architectures:
      - x86_64
    Environment:
      Variables:
        JAVA_TOOL_OPTIONS: -XX:+TieredCompilation -XX:TieredStopAtLevel=1
    Tags:
      Project: MyJavaApi

Parameters:
  Stage:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - staging
      - prod

Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub '${AWS::StackName}-api'
      CodeUri: build/libs/function.jar
      Handler: com.example.Handler
      Description: Java Lambda API Handler
      AutoPublishAlias: live
      DeploymentPreference:
        Type: Canary10Percent5Minutes
        Alarms:
          - !Ref ErrorsAlarm
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /{proxy+}
            Method: ANY
            RestApiId: !Ref ApiGateway
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref UsersTable
        - Statement:
            - Effect: Allow
              Action:
                - cloudwatch:PutMetricData
              Resource: '*'

  ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      Name: !Sub '${AWS::StackName}-api'
      StageName: !Ref Stage
      Cors:
        AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
        AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
        AllowOrigin: "'*'"
      TracingEnabled: true
      MethodSettings:
        - ResourcePath: /*
          HttpMethod: '*'
          LoggingLevel: INFO
          DataTraceEnabled: true
          MetricsEnabled: true

  UsersTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: !Sub '${AWS::StackName}-users'
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      KeySchema:
        - AttributeName: id
          KeyType: HASH
      PointInTimeRecoverySpecification:
        PointInTimeRecoveryEnabled: !If [IsProd, true, false]

  ErrorsAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub '${AWS::StackName}-errors'
      MetricName: Errors
      Namespace: AWS/Lambda
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 1
      Threshold: 1
      ComparisonOperator: GreaterThanOrEqualToThreshold
      Dimensions:
        - Name: FunctionName
          Value: !Ref ApiFunction

Conditions:
  IsProd: !Equals [!Ref Stage, prod]

Outputs:
  ApiUrl:
    Description: API Gateway URL
    Value: !Sub 'https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/${Stage}/'

  FunctionArn:
    Description: Lambda Function ARN
    Value: !GetAtt ApiFunction.Arn
    Export:
      Name: !Sub '${AWS::StackName}-function-arn'
```

### SAM with Layers

```yaml
Resources:
  # Lambda Layer for common dependencies
  DependenciesLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: java-dependencies
      Description: Common Java dependencies
      ContentUri: build/layers/dependencies/
      CompatibleRuntimes:
        - java21
      RetentionPolicy: Retain

  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/function.jar
      Handler: com.example.Handler
      Layers:
        - !Ref DependenciesLayer
      Environment:
        Variables:
          JAVA_TOOL_OPTIONS: -cp /opt/java/lib/*:lib/*
```

### SAM Local Testing

```yaml
# samconfig.toml
version = 0.1

[default]
[default.global.parameters]
stack_name = java-lambda-api

[default.build.parameters]
cached = true
parallel = true

[default.validate.parameters]
lint = true

[default.deploy.parameters]
capabilities = CAPABILITY_IAM
confirm_changeset = true
resolve_s3 = true
s3_prefix = java-lambda-api

[default.local_start_api.parameters]
warm_containers = EAGER

[default.local_invoke.parameters]
parameter_overrides = "Stage=local"
```

---

## CI/CD Pipeline

### GitHub Actions - Full Pipeline

```yaml
# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  JAVA_VERSION: '21'
  AWS_REGION: us-east-1

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          java-version: ${{ env.JAVA_VERSION }}
          distribution: 'temurin'
          cache: gradle

      - name: Run tests
        run: ./gradlew test

      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          files: build/reports/jacoco/test/jacocoTestReport.xml

  build:
    needs: test
    runs-on: ubuntu-latest
    outputs:
      artifact-path: ${{ steps.build.outputs.artifact-path }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          java-version: ${{ env.JAVA_VERSION }}
          distribution: 'temurin'
          cache: gradle

      - name: Build JAR
        id: build
        run: |
          ./gradlew shadowJar
          echo "artifact-path=build/libs/$(ls build/libs/*.jar | head -n 1)" >> $GITHUB_OUTPUT

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: lambda-jar
          path: build/libs/*.jar
          retention-days: 1

  deploy-dev:
    needs: build
    runs-on: ubuntu-latest
    environment: development
    if: github.ref == 'refs/heads/develop'
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: lambda-jar
          path: build/libs/

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Deploy with Serverless
        run: |
          npm install -g serverless
          serverless deploy --stage dev --region $AWS_REGION

  deploy-staging:
    needs: build
    runs-on: ubuntu-latest
    environment: staging
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: lambda-jar
          path: build/libs/

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Deploy with SAM
        run: |
          sam build
          sam deploy \
            --stack-name java-api-staging \
            --s3-bucket $DEPLOYMENT_BUCKET \
            --region $AWS_REGION \
            --capabilities CAPABILITY_IAM \
            --parameter-overrides Stage=staging \
            --no-confirm-changeset

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: lambda-jar
          path: build/libs/

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Deploy to Production
        run: |
          sam deploy \
            --stack-name java-api-prod \
            --s3-bucket $DEPLOYMENT_BUCKET \
            --region $AWS_REGION \
            --capabilities CAPABILITY_IAM \
            --parameter-overrides Stage=prod \
            --no-confirm-changeset
```

### GitHub Actions - SAM Only

```yaml
# .github/workflows/sam-pipeline.yml
name: SAM Pipeline

on:
  push:
    branches: [main]
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deployment environment'
        required: true
        default: 'staging'
        type: choice
        options:
          - staging
          - production

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4

      - uses: aws-actions/setup-sam@v2
        with:
          use-installer: true

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
          aws-region: us-east-1

      - uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '21'
          cache: gradle

      - name: Build application
        run: ./gradlew shadowJar

      - name: SAM Build
        run: sam build

      - name: SAM Deploy
        run: |
          sam deploy \
            --stack-name java-api-${{ github.event.inputs.environment || 'staging' }} \
            --resolve-s3 \
            --capabilities CAPABILITY_IAM \
            --parameter-overrides Stage=${{ github.event.inputs.environment || 'staging' }} \
            --no-confirm-changeset \
            --no-fail-on-empty-changeset
```

---

## Provisioned Concurrency

### Serverless Framework

```yaml
functions:
  api:
    handler: com.example.Handler
    provisionedConcurrency: 10
    events:
      - http:
          path: /{proxy+}
          method: ANY

    # Scheduled scaling (optional)
    provisionedConcurrencyScalers:
      - schedule: cron(0 9 * * ? *)
        value: 20
      - schedule: cron(0 18 * * ? *)
        value: 5
```

### SAM Template

```yaml
Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/function.jar
      Handler: com.example.Handler
      AutoPublishAlias: live
      ProvisionedConcurrencyConfig:
        ProvisionedConcurrentExecutions: 10

  # Scheduled scaling with Application Auto Scaling
  ScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    Properties:
      MaxCapacity: 50
      MinCapacity: 5
      ResourceId: !Sub 'function:${ApiFunction}:live'
      RoleARN: !Sub 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/lambda.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_LambdaConcurrency'
      ScalableDimension: lambda:function:ProvisionedConcurrency
      ServiceNamespace: lambda

  ScalingPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    Properties:
      PolicyName: lambda-provisioned-concurrency-policy
      PolicyType: TargetTrackingScaling
      ScalingTargetId: !Ref ScalableTarget
      TargetTrackingScalingPolicyConfiguration:
        TargetValue: 0.7
        PredefinedMetricSpecification:
          PredefinedMetricType: LambdaProvisionedConcurrencyUtilization
```

### Auto Scaling Based on Schedule

```yaml
Resources:
  BusinessHoursScaleUp:
    Type: AWS::AutoScaling::ScheduledAction
    Properties:
      AutoScalingGroupName: !Ref ScalableTarget
      MinSize: 20
      MaxSize: 50
      Recurrence: 0 9 * * MON-FRI
      TimeZone: America/New_York

  BusinessHoursScaleDown:
    Type: AWS::AutoScaling::ScheduledAction
    Properties:
      AutoScalingGroupName: !Ref ScalableTarget
      MinSize: 5
      MaxSize: 50
      Recurrence: 0 18 * * MON-FRI
      TimeZone: America/New_York
```

---

## Monitoring

### CloudWatch Alarms

```yaml
Resources:
  HighErrorRateAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub '${AWS::StackName}-high-error-rate'
      AlarmDescription: Error rate exceeds 1%
      MetricName: Errors
      Namespace: AWS/Lambda
      Statistic: Sum
      Period: 300
      EvaluationPeriods: 2
      Threshold: 10
      ComparisonOperator: GreaterThanThreshold
      TreatMissingData: notBreaching
      Dimensions:
        - Name: FunctionName
          Value: !Ref ApiFunction

  HighDurationAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub '${AWS::StackName}-high-duration'
      AlarmDescription: Average duration exceeds 5 seconds
      MetricName: Duration
      Namespace: AWS/Lambda
      Statistic: Average
      Period: 300
      EvaluationPeriods: 2
      Threshold: 5000
      ComparisonOperator: GreaterThanThreshold
      Dimensions:
        - Name: FunctionName
          Value: !Ref ApiFunction

  ThrottlingAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub '${AWS::StackName}-throttling'
      MetricName: Throttles
      Namespace: AWS/Lambda
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 1
      Threshold: 1
      ComparisonOperator: GreaterThanOrEqualToThreshold
      Dimensions:
        - Name: FunctionName
          Value: !Ref ApiFunction
```

### Custom Metrics

```java
// Emit custom metrics from Lambda
private void emitMetric(String name, double value, String unit) {
    PutMetricDataRequest request = PutMetricDataRequest.builder()
        .namespace("MyApplication")
        .metricData(MetricDatum.builder()
            .metricName(name)
            .value(value)
            .unit(unit)
            .dimensions(
                Dimension.builder().name("Function").value("ApiHandler").build(),
                Dimension.builder().name("Stage").value(System.getenv("STAGE")).build()
            )
            .build())
        .build();

    cloudWatchClient.putMetricData(request);
}

// Usage
emitMetric("ProcessingTime", duration, StandardUnit.MILLISECONDS);
emitMetric("ItemsProcessed", count, StandardUnit.Count);
```

### X-Ray Tracing

```yaml
Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      Tracing: Active
      Environment:
        Variables:
          AWS_XRAY_CONTEXT_MISSING: LOG_ERROR
```

```java
// Add subsegments for detailed tracing
import com.amazonaws.xray.AWSXRay;
import com.amazonaws.xray.entities.Subsegment;

public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent request, Context context) {
    Subsegment subsegment = AWSXRay.beginSubsegment("ProcessRequest");
    try {
        // Business logic
        subsegment.putAnnotation("userId", userId);
        subsegment.putMetadata("request", Map.of("path", request.getPath()));

        return processRequest(request);
    } catch (Exception e) {
        subsegment.addException(e);
        throw e;
    } finally {
        AWSXRay.endSubsegment();
    }
}
```

### CloudWatch Logs Insights Queries

```sql
-- Find cold starts
fields @timestamp, @message, @duration
| filter @message like /INIT_START/
| stats count() as cold_starts by bin(5m)

-- Average duration by stage
fields @duration, @memorySize
| filter @type = "REPORT"
| stats avg(@duration), max(@duration), min(@duration) by @memorySize

-- Error analysis
fields @timestamp, @message
| filter @message like /ERROR/
| stats count() as errors by bin(1h)
| sort by @timestamp desc

-- Performance by endpoint (requires custom logging)
fields @timestamp, @message
| parse @message "path: *, duration: *ms" as path, duration
| stats avg(duration), max(duration), count() by path
| sort by avg(duration) desc
```

---

## Build Optimization

### Gradle Configuration

```groovy
// build.gradle
plugins {
    id 'java'
    id 'com.github.johnrengelman.shadow' version '8.1.1'
}

java {
    sourceCompatibility = JavaVersion.VERSION_21
    targetCompatibility = JavaVersion.VERSION_21
}

// Optimized build task for Lambda deployment packages
task buildZip(type: Zip) {
    from compileJava
    from processResources
    into('lib') {
        from configurations.runtimeClasspath
    }
    archiveFileName = "${project.name}-${project.version}.zip"
}

// Shadow JAR with minimized dependencies
shadowJar {
    archiveClassifier = ''
    mergeServiceFiles()

    // Exclude unnecessary files to reduce JAR size
    exclude 'META-INF/*.SF'
    exclude 'META-INF/*.DSA'
    exclude 'META-INF/*.RSA'
    exclude 'META-INF/LICENSE*'
    exclude 'META-INF/NOTICE*'

    // Minimize to only include used classes
    minimize()
}

dependencies {
    // AWS SDK v2 - include only needed modules
    implementation 'software.amazon.awssdk:dynamodb:2.25.0'
    implementation 'software.amazon.awssdk:s3:2.25.0'
    implementation 'software.amazon.awssdk:lambda:2.25.0'

    // Avoid entire AWS SDK - do NOT use:
    // implementation 'software.amazon.awssdk:aws-sdk-java:2.25.0'

    // Prefer lightweight DI frameworks over Spring
    implementation 'com.google.dagger:dagger:2.51'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.51'

    // Or use Guice if needed
    // implementation 'com.google.inject:guice:7.0.0'

    // Lambda runtime
    implementation 'com.amazonaws:aws-lambda-java-core:1.2.3'
    implementation 'com.amazonaws:aws-lambda-java-events:3.11.4'

    // Logging (lightweight)
    implementation 'org.slf4j:slf4j-simple:2.0.12'
}
```

### Maven Configuration

```xml
<!-- pom.xml -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.12.1</version>
            <configuration>
                <source>21</source>
                <target>21</target>
            </configuration>
        </plugin>

        <!-- Maven Shade Plugin for creating uber JAR -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <createDependencyReducedPom>false</createDependencyReducedPom>
                <filters>
                    <filter>
                        <artifact>*:*</artifact>
                        <excludes>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                            <exclude>META-INF/LICENSE*</exclude>
                            <exclude>META-INF/NOTICE*</exclude>
                        </excludes>
                    </filter>
                </filters>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <minimizeJar>true</minimizeJar>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

<dependencies>
    <!-- AWS SDK v2 - selective modules only -->
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>dynamodb</artifactId>
        <version>2.25.0</version>
    </dependency>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
        <version>2.25.0</version>
    </dependency>

    <!-- Lambda runtime -->
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-lambda-java-core</artifactId>
        <version>1.2.3</version>
    </dependency>
</dependencies>
```

### Handler Separation Pattern

```java
// Separate Lambda handler from core business logic
public class LambdaHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    private final OrderService orderService;

    // Constructor for Lambda runtime (with dependency injection)
    public LambdaHandler() {
        this.orderService = DaggerOrderComponent.create().orderService();
    }

    // Constructor for testing
    public LambdaHandler(OrderService orderService) {
        this.orderService = orderService;
    }

    @Override
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent request, Context context) {
        // Delegate to core logic
        return orderService.processOrder(request);
    }
}

// Core business logic separate from Lambda infrastructure
public class OrderService {
    private final OrderRepository repository;
    private final NotificationService notificationService;

    @Inject
    public OrderService(OrderRepository repository, NotificationService notificationService) {
        this.repository = repository;
        this.notificationService = notificationService;
    }

    public APIGatewayProxyResponseEvent processOrder(APIGatewayProxyRequestEvent request) {
        // Business logic here - can be tested independently
    }
}
```

---

## Package Optimization

### Lambda Layers for Java Dependencies

```yaml
# SAM template with Lambda Layers
Resources:
  # Shared dependencies layer
  DependenciesLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: java-common-dependencies
      Description: Common Java dependencies for Lambda functions
      ContentUri: build/layers/dependencies/
      CompatibleRuntimes:
        - java21
      RetentionPolicy: Retain

  # Function using the layer
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/function.jar
      Handler: com.example.Handler
      Layers:
        - !Ref DependenciesLayer
      Environment:
        Variables:
          JAVA_TOOL_OPTIONS: -cp /opt/java/lib/*:lib/*
```

```groovy
// build.gradle - Create layer structure
task buildLayer(type: Copy) {
    from configurations.runtimeClasspath
    into "build/layers/dependencies/java/lib"

    // Exclude AWS SDK provided by Lambda runtime
    exclude 'aws-lambda-java-core*.jar'
    exclude 'aws-lambda-java-events*.jar'
}

// Build minimal function JAR (business logic only)
task buildFunctionJar(type: Jar) {
    from sourceSets.main.output
    exclude '**/lib/**'
    archiveFileName = "function.jar"
}
```

### JAR Size Reduction Techniques

```groovy
// Exclude unnecessary dependencies
dependencies {
    implementation('com.fasterxml.jackson.core:jackson-databind:2.16.0') {
        // Exclude unused Jackson modules
        exclude group: 'com.fasterxml.jackson.module'
    }

    // Use ProGuard for aggressive optimization (advanced)
    // buildscript { dependencies { classpath 'com.guardsquare:proguard-gradle:7.4.0' } }
}

// Gradle configuration for minimal JAR
jar {
    enabled = false  // Disable standard JAR, use shadow only
}

shadowJar {
    // Remove unused classes
    minimize {
        exclude(dependency('org.slf4j:.*:.*'))
    }

    // Relocate packages to avoid conflicts
    relocate 'com.fasterxml.jackson', 'shaded.com.fasterxml.jackson'
}
```

### Maven Dependency Copy for Layer

```xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>3.6.1</version>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/layers/java/lib</outputDirectory>
                <includeScope>runtime</includeScope>
                <excludeArtifactIds>aws-lambda-java-core,aws-lambda-java-events</excludeArtifactIds>
            </configuration>
        </execution>
    </executions>
</plugin>
```

---

## Performance Tuning

### JVM Options for Lambda

```yaml
Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: java21
      Environment:
        Variables:
          # Optimized JVM flags for Lambda cold starts
          JAVA_TOOL_OPTIONS: >
            -XX:+TieredCompilation
            -XX:TieredStopAtLevel=1
            -XX:+UseSerialGC
            -XX:MaxRAMPercentage=75.0
            -XX:InitialRAMPercentage=50.0
```

**JVM Option Explanations:**

| Option | Purpose | Impact |
|--------|---------|--------|
| `-XX:+TieredCompilation` | Enable tiered compilation | Faster startup |
| `-XX:TieredStopAtLevel=1` | Stop at C1 compiler only | Reduced compilation time |
| `-XX:+UseSerialGC` | Use single-threaded GC | Lower memory overhead |
| `-XX:MaxRAMPercentage=75.0` | Limit heap to 75% of container memory | Prevent OOM |

### Memory Configuration Guidance

```yaml
# Memory allocation vs vCPU allocation
# 1769MB = 1 vCPU (linear scaling below this threshold)

Resources:
  LowMemoryFunction:
    Type: AWS::Serverless::Function
    Properties:
      MemorySize: 512
      # Suitable for: Simple CRUD, low throughput

  BalancedFunction:
    Type: AWS::Serverless::Function
    Properties:
      MemorySize: 1024
      # Good balance of performance and cost

  HighPerformanceFunction:
    Type: AWS::Serverless::Function
    Properties:
      MemorySize: 1769
      # 1 full vCPU - optimal for CPU-intensive tasks

  MaximumPerformanceFunction:
    Type: AWS::Serverless::Function
    Properties:
      MemorySize: 3008
      # 2 vCPUs - for compute-intensive operations
```

### Cold Start Optimization

```java
public class OptimizedHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    // Initialize heavy resources statically (during init phase)
    private static final DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
        .httpClientBuilder(UrlConnectionHttpClient.builder())  // Lightweight HTTP client
        .build();

    private static final ObjectMapper objectMapper = new ObjectMapper()
        .registerModule(new JavaTimeModule());

    // Initialize during first invocation if needed
    private final OrderRepository orderRepository;

    public OptimizedHandler() {
        // This runs during init phase (not counted in billing)
        this.orderRepository = new OrderRepository(dynamoDbClient);
    }

    @Override
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent request, Context context) {
        // Handler execution - reuse initialized resources
        return processRequest(request);
    }
}
```

### Connection Pool Settings

```java
// HTTP client configuration for Lambda
public class HttpClientConfig {

    public static HttpClient createOptimizedClient() {
        return HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(5))
            .version(HttpClient.Version.HTTP_2)
            .build();
    }
}

// Database connection pooling (if using RDS Proxy or direct connections)
public class DatabaseConfig {

    public static HikariDataSource createDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(System.getenv("DB_URL"));
        config.setUsername(System.getenv("DB_USER"));
        config.setPassword(System.getenv("DB_PASSWORD"));

        // Lambda-optimized pool settings
        config.setMaximumPoolSize(2);  // Keep minimal for Lambda
        config.setMinimumIdle(0);      // Don't maintain idle connections
        config.setIdleTimeout(10000);  // 10 second idle timeout
        config.setConnectionTimeout(5000);
        config.setMaxLifetime(300000); // 5 minutes max lifetime

        return new HikariDataSource(config);
    }
}
```

---

## Rollback Strategy

### AWS SAM with CodeDeploy Integration

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/function.jar
      Handler: com.example.Handler
      Runtime: java21
      AutoPublishAlias: live  # Required for traffic shifting

      # Deployment preferences with automatic rollback
      DeploymentPreference:
        Type: Canary10Percent5Minutes
        Alarms:
          - !Ref ErrorRateAlarm
          - !Ref LatencyAlarm
        Hooks:
          PreTraffic: !Ref PreTrafficHookFunction
          PostTraffic: !Ref PostTrafficHookFunction

  # Pre-traffic hook for validation
  PreTrafficHookFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/hooks.jar
      Handler: com.example.hooks.PreTrafficHook
      Runtime: java21
      Policies:
        - Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - codedeploy:PutLifecycleEventHookExecutionStatus
              Resource: '*'

  # Post-traffic hook for verification
  PostTrafficHookFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/hooks.jar
      Handler: com.example.hooks.PostTrafficHook
      Runtime: java21
      Policies:
        - Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Action:
                - codedeploy:PutLifecycleEventHookExecutionStatus
              Resource: '*'

  # Alarms for automatic rollback triggers
  ErrorRateAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub '${AWS::StackName}-error-rate'
      MetricName: Errors
      Namespace: AWS/Lambda
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 2
      Threshold: 5
      ComparisonOperator: GreaterThanThreshold
      Dimensions:
        - Name: FunctionName
          Value: !Ref ApiFunction

  LatencyAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub '${AWS::StackName}-latency'
      MetricName: Duration
      Namespace: AWS/Lambda
      Statistic: Average
      Period: 60
      EvaluationPeriods: 2
      Threshold: 3000
      ComparisonOperator: GreaterThanThreshold
```

### Deployment Types

```yaml
# Canary deployments - shift traffic gradually
DeploymentPreference:
  Type: Canary10Percent5Minutes  # 10% for 5 minutes, then 100%
  # Other options:
  # - Canary10Percent30Minutes
  # - Canary10Percent5Minutes
  # - Canary10Percent10Minutes
  # - Canary10Percent15Minutes

# Linear deployments - shift traffic in increments
DeploymentPreference:
  Type: Linear10PercentEvery1Minute  # 10% per minute until 100%
  # Other options:
  # - Linear10PercentEvery2Minutes
  # - Linear10PercentEvery3Minutes
  # - Linear10PercentEvery10Minutes

# All-at-once (no rollback capability)
DeploymentPreference:
  Type: AllAtOnce
```

### Pre/Post Traffic Hook Implementation

```java
// Pre-traffic hook for smoke tests
public class PreTrafficHook implements RequestHandler<Map<String, Object>, String> {

    private final CodeDeployClient codeDeployClient;
    private final HttpClient httpClient;

    public PreTrafficHook() {
        this.codeDeployClient = CodeDeployClient.create();
        this.httpClient = HttpClient.newHttpClient();
    }

    @Override
    public String handleRequest(Map<String, Object> event, Context context) {
        String deploymentId = (String) event.get("DeploymentId");
        String lifecycleEventHookExecutionId = (String) event.get("LifecycleEventHookExecutionId");

        try {
            // Run smoke tests against the new version
            boolean testsPassed = runSmokeTests();

            // Report status to CodeDeploy
            PutLifecycleEventHookExecutionStatusRequest statusRequest =
                PutLifecycleEventHookExecutionStatusRequest.builder()
                    .deploymentId(deploymentId)
                    .lifecycleEventHookExecutionId(lifecycleEventHookExecutionId)
                    .status(testsPassed ? LifecycleEventStatus.SUCCEEDED : LifecycleEventStatus.FAILED)
                    .build();

            codeDeployClient.putLifecycleEventHookExecutionStatus(statusRequest);

            return testsPassed ? "Success" : "Failure";

        } catch (Exception e) {
            context.getLogger().log("Pre-traffic hook failed: " + e.getMessage());

            // Report failure to trigger rollback
            codeDeployClient.putLifecycleEventHookExecutionStatus(
                PutLifecycleEventHookExecutionStatusRequest.builder()
                    .deploymentId(deploymentId)
                    .lifecycleEventHookExecutionId(lifecycleEventHookExecutionId)
                    .status(LifecycleEventStatus.FAILED)
                    .build()
            );

            throw new RuntimeException(e);
        }
    }

    private boolean runSmokeTests() {
        // Implement smoke tests (health check, basic functionality)
        return true;
    }
}
```

---

## Security Best Practices

### IAM Least Privilege

```yaml
Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/function.jar
      Handler: com.example.Handler
      Policies:
        # Use managed policies for common patterns
        - DynamoDBCrudPolicy:
            TableName: !Ref UsersTable

        # Custom least-privilege policy
        - Statement:
            - Effect: Allow
              Action:
                - s3:GetObject
                - s3:PutObject
              Resource:
                - !Sub 'arn:aws:s3:::${BucketName}/uploads/*'
              Condition:
                StringEquals:
                  s3:x-amz-acl: bucket-owner-full-control

        # Explicit deny for sensitive operations
            - Effect: Deny
              Action:
                - s3:DeleteBucket
                - dynamodb:DeleteTable
              Resource: '*'
```

### VPC Configuration

```yaml
Resources:
  VpcFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/function.jar
      Handler: com.example.Handler
      VpcConfig:
        SecurityGroupIds:
          - !Ref LambdaSecurityGroup
        SubnetIds:
          - !Ref PrivateSubnet1
          - !Ref PrivateSubnet2
      # VPC functions require NAT Gateway for internet access
      # or VPC endpoints for AWS services

  # Security group with minimal access
  LambdaSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Lambda security group
      VpcId: !Ref VPC
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
          Description: HTTPS to AWS services
        - IpProtocol: tcp
          FromPort: 5432
          ToPort: 5432
          DestinationSecurityGroupId: !Ref RdsSecurityGroup
          Description: PostgreSQL to RDS

  # VPC Endpoints for AWS services (avoid NAT Gateway costs)
  S3VpcEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
      VpcEndpointType: Gateway
      RouteTableIds:
        - !Ref PrivateRouteTable

  DynamoDbVpcEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.dynamodb'
      VpcEndpointType: Gateway
      RouteTableIds:
        - !Ref PrivateRouteTable
```

### Secrets Manager and SSM Parameter Store

```yaml
Resources:
  SecureFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: build/libs/function.jar
      Handler: com.example.Handler
      Environment:
        Variables:
          # Reference secrets by ARN (not value)
          DB_SECRET_ARN: !Ref DatabaseSecret
          API_KEY_PARAM: !Ref ApiKeyParameter
      Policies:
        - Statement:
            - Effect: Allow
              Action:
                - secretsmanager:GetSecretValue
              Resource: !Ref DatabaseSecret
            - Effect: Allow
              Action:
                - ssm:GetParameter
              Resource: !Ref ApiKeyParameter

  # Secrets Manager for database credentials
  Datab

…(truncated)
