Deploy AWS Lambda Functions with GitHub Actions
Automate the build, test, and deployment of AWS Lambda functions using GitHub Actions, with branch-based environments and optional rollback on health-check failure.
Prerequisites
- An AWS Lambda function already created
- An IAM user or role with the required permissions (see below)
- A GitHub repository containing your Lambda code
Let's Start
Step 1 — Project structure
Organize your Lambda project like this:
lambda-project/
├── .github/
│ └─ ─ workflows/
│ └── deploy.yml
├── src/
│ └── handlers/
│ └── example_handler.py
├── requirements.txt
└── README.md
Step 2 — Example Lambda function (Python)
import json
import os
import boto3
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
try:
table_name = os.environ.get('TABLE_NAME', 'default-table')
logger.info(f"Processing event: {json.dumps(event)}")
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(table_name)
table.put_item(Item={
'id': event.get('id', 'unknown'),
'data': event.get('data', {}),
'request_id': context.aws_request_id
})
return {
'statusCode': 200,
'body': json.dumps({'message': 'Success', 'request_id': context.aws_request_id})
}
except Exception as e:
logger.error(f"Error: {str(e)}", exc_info=True)
return {'statusCode': 500, 'body': json.dumps({'error': str(e)})}
Step 3 — GitHub Actions workflow
Create .github/workflows/deploy.yml:
name: Deploy Lambda
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
AWS_REGION: us-east-1
LAMBDA_FUNCTION_NAME: example-lambda
jobs:
deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
- name: Install dependencies
run: |
pip install -r requirements.txt -t ./package
cp -r src/* ./package/
- name: Create deployment package
run: |
cd package
zip -r ../lambda-deployment.zip .
- 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 Lambda
run: |
aws lambda update-function-code \
--function-name ${{ env.LAMBDA_FUNCTION_NAME }} \
--zip-file fileb://lambda-deployment.zip
- name: Update Lambda configuration
run: |
aws lambda update-function-configuration \
--function-name ${{ env.LAMBDA_FUNCTION_NAME }} \
--environment Variables="{TABLE_NAME=${{ secrets.DYNAMODB_TABLE }}}" \
--timeout 30 \
--memory-size 256
- name: Health check
run: |
aws lambda invoke \
--function-name ${{ env.LAMBDA_FUNCTION_NAME }} \
--payload '{"id": "health-check"}' \
response.json
status=$(jq -r '.statusCode' response.json)
if [ "$status" != "200" ]; then
echo "Health check failed (status: $status)"
exit 1
fi
Step 4 — Add secrets in GitHub
Go to Settings → Secrets and variables → Actions and add:
| Secret | Description |
|---|---|
AWS_ACCESS_KEY_ID | AWS access key |
AWS_SECRET_ACCESS_KEY | AWS secret key |
DYNAMODB_TABLE | DynamoDB table name (optional) |
Step 5 — Required IAM permissions
The IAM user or role used by GitHub Actions needs at minimum:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:UpdateFunctionCode",
"lambda:UpdateFunctionConfiguration",
"lambda:PublishVersion",
"lambda:UpdateAlias",
"lambda:InvokeFunction"
],
"Resource": "arn:aws:lambda:us-east-1:*:function:example-lambda"
}
]
}
Troubleshooting
Package too large: Use Lambda Layers for heavy dependencies:
aws lambda publish-layer-version \
--layer-name common-dependencies \
--zip-file fileb://dependencies-layer.zip \
--compatible-runtimes python3.11
aws lambda update-function-configuration \
--function-name example-lambda \
--layers arn:aws:lambda:us-east-1:123456789:layer:common-dependencies:1
Permission denied: Verify the IAM policy in Step 5 is attached to the role used by GitHub Actions.