This project demonstrates how to build an AWS CI/CD pipeline using GitHub Actions, AWS CDK (TypeScript), AWS Lambda (Python), and DynamoDB . It automates infrastructure deployment while incorporating AWS Lambda and DynamoDB to track and store website visits.
- ✅ AWS CDK: Defines infrastructure as code using TypeScript.
- ✅ GitHub Actions: Automates deployments and version updates.
- ✅ AWS Lambda: Runs a Python function for visit tracking.
- ✅ DynamoDB: Stores visit counts as a NoSQL database.
- ✅ Git Hooks: Automatically increments version numbers.
- Install AWS CLI and configure your AWS credentials:
aws configure - Install Node.js and AWS CDK globally:
npm install -g aws-cdk - Ensure Python 3.9+ is installed for the Lambda function.
- Enable GitHub Actions by adding AWS credentials as secrets in GitHub.
cdk init app --language typescript
In cicd-aws-stack.ts, define a Lambda function with DynamoDB access:
const lambdaFunction = new lambda.Function(this, "LambdaFunction", {
runtime: lambda.Runtime.PYTHON_3_9,
code: lambda.Code.fromAsset("lambda"),
handler: "main.handler",
environment: {
VERSION: process.env.VERSION || "0.0",
TABLE_NAME: table.tableName,
}
});
Define a DynamoDB table for visit tracking:
const table = new dynamodb.Table(this, "VisitorTimeTable", {
partitionKey: { name: "key", type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});
lambdaFunction.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE,
});
cdk bootstrap --region us-west-2 cdk synth cdk deploy
Workflows must be inside .github/workflows/. This setup:
- Caches dependencies for faster builds.
- Deploys the CDK stack using AWS credentials.
- Automatically updates the version.
To enable GitHub Actions deployment, add AWS credentials in GitHub:
GitHub Repo -> Settings -> Secrets and variables -> Actions -> New Repository Secret
Since .git is hidden, enable it and navigate to the hooks directory.
Copy and rename pre-commit.sample to pre-commit, then add this script:
#!/bin/sh
VERSION=$(sed -n 's/VERSION="\([^"]*\)"/\1/p' .env)
if [[ -n $VERSION ]]; then
IFS='.' read -ra ADDR <<< $VERSION
last_index=$((${#ADDR[@]} - 1))
ADDR[$last_index]=$((${ADDR[$last_index]} + 1))
NEW_VERSION=$(IFS=.; echo "${ADDR[*]}")
perl -pi -e "s/$VERSION/$NEW_VERSION/g" .env
echo "NEW version: $NEW_VERSION"
git add .env
fi
chmod +x .git/hooks/pre-commit
In the Lambda function, use Boto3 to interact with DynamoDB:
import boto3
import os
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table(os.environ["TABLE_NAME"])
def handler(event, context):
table.update_item(
Key={"key": "visitor_count"},
UpdateExpression="ADD visit_count :inc",
ExpressionAttributeValues={":inc": 1}
)
return {"statusCode": 200, "body": "Visit count updated!"}
Ensure only root paths increase the visit count:
if event["rawPath"] != "/":
return {"statusCode": 404, "body": "Not Found"}
Inspired by this tutorial.


