Skip to content

CI/CD integration

Automate your Lambda function builds and deployments using popular CI/CD platforms. These examples show how to build and deploy Lambda functions with Powertools for AWS with proper cross-platform compatibility and deploy them reliably.

GitHub Actions

GitHub Actions provides a powerful, integrated CI/CD platform that runs directly in your GitHub repository. It offers excellent integration with AWS services, supports matrix builds for testing multiple configurations, and provides a rich ecosystem of pre-built actions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
name: Deploy Lambda with AWS Lambda Deploy Action

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

env:
  AWS_REGION: us-east-1
  PYTHON_VERSION: '3.13'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # v5.0.0

    - name: Set up Python
      uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
      with:
        python-version: ${{ env.PYTHON_VERSION }}

    - name: Install dependencies
      run: |
        pip install aws-lambda-powertools[all] pytest pytest-cov

    - name: Run tests
      run: |
        pytest tests/ --cov=src/ --cov-report=xml

    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v4
      with:
        file: ./coverage.xml

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
    - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # v5.0.0

    - name: Set up Python
      uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
      with:
        python-version: ${{ env.PYTHON_VERSION }}

    - name: Prepare deployment directory
      run: |
        # Create deployment directory with dependencies
        mkdir -p deploy/

        # Install dependencies with Linux-compatible wheels
        pip install \
          --platform manylinux2014_x86_64 \
          --target deploy/ \
          --implementation cp \
          --python-version ${{ env.PYTHON_VERSION }} \
          --only-binary=:all: \
          --upgrade \
          aws-lambda-powertools[all] pydantic requests

        # Copy application code
        cp -r src/* deploy/

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
        aws-region: ${{ env.AWS_REGION }}

    - name: Deploy to Lambda
      uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d
      with:
        function-name: powertools-lambda-function
        code-artifacts-dir: deploy/
        handler: app.lambda_handler
        runtime: python3.13
        environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-app","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}'
        timeout: 30
        memory-size: 512
        role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
name: Multi-Environment Lambda Deployment

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

jobs:
  deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        include:
          - branch: develop
            environment: dev
            function-suffix: -dev
            memory: 256
            timeout: 30
            log-level: DEBUG
          - branch: staging
            environment: staging
            function-suffix: -staging
            memory: 512
            timeout: 45
            log-level: INFO
          - branch: main
            environment: prod
            function-suffix: -prod
            memory: 1024
            timeout: 60
            log-level: INFO

    steps:
    - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # v5.0.0
      if: github.ref == format('refs/heads/{0}', matrix.branch)

    - name: Set up Python
      if: github.ref == format('refs/heads/{0}', matrix.branch)
      uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
      with:
        python-version: '3.13'

    - name: Prepare deployment with uv (fast)
      if: github.ref == format('refs/heads/{0}', matrix.branch)
      run: |
        # Install uv for fast dependency management
        pip install uv

        # Create deployment directory
        mkdir -p deploy-${{ matrix.environment }}/

        # Install dependencies with uv (much faster than pip)
        uv pip install \
          --target deploy-${{ matrix.environment }}/ \
          --python-version 3.13 \
          --platform manylinux2014_x86_64 --only-binary=:all: \
          aws-lambda-powertools[all] pydantic requests

        # Copy application code
        cp -r src/* deploy-${{ matrix.environment }}/

    - name: Configure AWS credentials
      if: github.ref == format('refs/heads/{0}', matrix.branch)
      uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
        aws-region: us-east-1

    - name: Deploy to Lambda
      if: github.ref == format('refs/heads/{0}', matrix.branch)
      uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d # v1.0.1
      with:
        function-name: powertools-app${{ matrix.function-suffix }}
        code-artifacts-dir: deploy-${{ matrix.environment }}/
        handler: app.lambda_handler
        runtime: python3.13
        environment: '{"ENVIRONMENT":"${{ matrix.environment }}","POWERTOOLS_SERVICE_NAME":"powertools-app-${{ matrix.environment }}","POWERTOOLS_METRICS_NAMESPACE":"MyApp/${{ matrix.environment }}","POWERTOOLS_LOG_LEVEL":"${{ matrix.log-level }}"}'
        timeout: ${{ matrix.timeout }}
        memory-size: ${{ matrix.memory }}
        role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }}
        tags: '{"Environment":"${{ matrix.environment }}","Project":"powertools-demo","ManagedBy":"github-actions"}'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
name: Simple Lambda Deployment from Source

on:
  push:
    branches: [main]

env:
  AWS_REGION: us-east-1

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # v5.0.0

    - name: Set up Python
      uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
      with:
        python-version: '3.13'

    - name: Install dependencies
      run: |
        # Simple pip install - the action handles the rest
        pip install --platform manylinux2014_x86_64 --only-binary=:all: \
        --python-version 3.13 -r requirements.txt -t src-deploy/

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
        aws-region: ${{ env.AWS_REGION }}

    - name: Deploy to Lambda
      uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d
      with:
        function-name: powertools-simple-function
        code-artifacts-dir: src-deploy/  # Deploy from current directory
        handler: app.lambda_handler
        runtime: python3.13
        environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-simple","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}'
        timeout: 30
        memory-size: 512
        role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }}
        dry-run: false  # Set to true for validation without deployment
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
name: Deploy Lambda via S3

on:
  push:
    branches: [main]

env:
  AWS_REGION: us-east-1
  S3_BUCKET: my-lambda-deployments-bucket

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # v5.0.0

    - name: Set up Python
      uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
      with:
        python-version: '3.13'

    - name: Prepare deployment directory
      run: |
        mkdir -p lambda-package/

        # Install Powertools and dependencies
        pip install \
          --platform manylinux2014_x86_64 \
          --target lambda-package/ \
          --implementation cp \
          --python-version 3.13 \
          --only-binary=:all: \
          aws-lambda-powertools[all] pydantic requests

        # Copy source code
        cp -r src/* lambda-package/

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
        aws-region: ${{ env.AWS_REGION }}

    - name: Deploy to Lambda via S3
      uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d # v1.0.1
      with:
        function-name: powertools-s3-function
        code-artifacts-dir: lambda-package/
        handler: app.lambda_handler
        runtime: python3.13
        s3-bucket: ${{ env.S3_BUCKET }}
        s3-key: deployments/powertools-function-${{ github.sha }}.zip
        environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-s3","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}'
        timeout: 30
        memory-size: 512
        role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }}
        publish: true  # Publish a new version
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
name: Deploy with Different Build Tools

on:
  push:
    branches: [main]

jobs:
  deploy-poetry:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # v5.0.0

    - name: Set up Python
      uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
      with:
        python-version: '3.13'

    - name: Install Poetry
      run: pip install --upgrade pip poetry

    - name: Build with Poetry
      run: |
        # Create deployment directory
        mkdir -p poetry-deploy/

        # Export and install dependencies
        poetry export -f requirements.txt --output requirements.txt --without-hashes
        pip install --platform manylinux2014_x86_64 --only-binary=:all: \
        --python-version 3.13 -r requirements.txt -t poetry-deploy/

        # Copy source code
        cp -r src/* poetry-deploy/

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
        aws-region: us-east-1

    - name: Deploy Poetry build
      uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d
      with:
        function-name: powertools-poetry-function
        code-artifacts-dir: poetry-deploy/
        handler: app.lambda_handler
        runtime: python3.13
        environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-poetry","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}'
        role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }}

  deploy-uv:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8  # v5.0.0

    - name: Set up Python
      uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
      with:
        python-version: '3.13'

    - name: Build with uv (fastest)
      run: |
        # Install uv
        pip install uv

        # Create deployment directory
        mkdir -p uv-deploy/

        # Install dependencies with uv (much faster)
        uv pip install \
          --target uv-deploy/ \
          --python-version 3.13 \
          --platform manylinux2014_x86_64 --only-binary=:all: \
          aws-lambda-powertools[all] pydantic requests

        # Copy source code
        cp -r src/* uv-deploy/

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@209f2a4450bb4b277e1dedaff40ad2fd8d4d0a4c # v4.3.0
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
        aws-region: us-east-1

    - name: Deploy uv build
      uses: aws-actions/aws-lambda-deploy@246115fccc1ad110c97f729696574d09eb5c690d # v1.0.1
      with:
        function-name: powertools-uv-function
        code-artifacts-dir: uv-deploy/
        handler: app.lambda_handler
        runtime: python3.13
        environment: '{"POWERTOOLS_SERVICE_NAME":"powertools-uv","POWERTOOLS_METRICS_NAMESPACE":"MyApp","POWERTOOLS_LOG_LEVEL":"INFO"}'
        role: ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }}

AWS CodeBuild

AWS CodeBuild is a fully managed build service that compiles source code, runs tests, and produces deployment packages. It integrates seamlessly with other AWS services and provides consistent build environments with automatic scaling.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
version: 0.2

env:
  variables:
    PYTHON_VERSION: "3.13"
    POWERTOOLS_VERSION: "3.18.0"
  parameter-store:
    FUNCTION_NAME: "/lambda/powertools-app/function-name"

phases:
  install:
    runtime-versions:
      python: $PYTHON_VERSION
    commands:
      - echo "Installing build dependencies..."
      - pip install --upgrade pip
      - pip install uv poetry  # Install fast package managers

  pre_build:
    commands:
      - echo "Pre-build phase started on $(date)"
      - echo "Python version: $(python --version)"
      - echo "Installing application dependencies..."

      # Use uv for fast dependency installation
      - uv venv build-env
      - source build-env/bin/activate
      - uv pip install aws-lambda-powertools[all]==$POWERTOOLS_VERSION
      - uv pip install pydantic requests

  build:
    commands:
      - echo "Build started on $(date)"
      - echo "Creating deployment package..."

      # Create optimized deployment package
      - mkdir -p package/
      - cp -r build-env/lib/python*/site-packages/* package/
      - cp -r src/* package/

      # Remove unnecessary files to reduce package size
      - find package/ -name "*.pyc" -delete
      - find package/ -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true
      - find package/ -name "tests" -type d -exec rm -rf {} + 2>/dev/null || true
      - find package/ -name "*.dist-info" -type d -exec rm -rf {} + 2>/dev/null || true

      # Create deployment ZIP
      - cd package && zip -r ../lambda-deployment.zip . && cd ..

      # Show package info
      - echo "Package size: $(du -sh lambda-deployment.zip)"
      - echo "Package contents:"
      - unzip -l lambda-deployment.zip | head -20

  post_build:
    commands:
      - echo "Build completed on $(date)"
      - echo "Deploying Lambda function..."

      # Deploy to Lambda
      - aws lambda update-function-code \
          --function-name $FUNCTION_NAME \
          --zip-file fileb://lambda-deployment.zip \
          --region $AWS_DEFAULT_REGION

      # Update environment variables
      - aws lambda update-function-configuration \
          --function-name $FUNCTION_NAME \
          --environment Variables="{
            POWERTOOLS_SERVICE_NAME=powertools-codebuild,
            POWERTOOLS_METRICS_NAMESPACE=MyApp/CodeBuild,
            POWERTOOLS_LOG_LEVEL=INFO
          }" \
          --region $AWS_DEFAULT_REGION

      - echo "Deployment completed successfully!"

artifacts:
  files:
    - lambda-deployment.zip
  name: lambda-deployment-$(date +%Y-%m-%d-%H-%M-%S)

cache:
  paths:
    - 'build-env/**/*'  # Cache virtual environment for faster builds

Best Practices for CI/CD

  1. Use Linux runners (ubuntu-latest) to ensure Lambda compatibility
  2. Cache dependencies to speed up builds (uv, poetry cache, pip cache)
  3. Run tests first before building deployment packages
  4. Use matrix builds to test multiple Python versions or configurations
  5. Implement proper secrets management with GitHub Secrets or AWS Parameter Store
  6. Add deployment gates for production environments
  7. Monitor deployment success with CloudWatch metrics and alarms
Performance Optimization
  • Use uv for fastest dependency installation in CI/CD
  • Cache virtual environments between builds when possible
  • Parallelize builds for multiple environments
  • Use container images for complex dependencies or large packages