AWS Certified Developer Associate (DVA-C02) 2025: Complete Exam Guide for Developers
An interviewer asks: "Your Lambda function occasionally fails with timeout errors. How do you debug this in production?" Most candidates freeze or suggest generic logging. The interviewer wants specifics: CloudWatch Logs Insights, X-Ray tracing, custom metrics, dead letter queues, and concurrent execution analysis.
The AWS Certified Developer Associate (DVA-C02) exam tests whether you can actually build, deploy, and debug applications on AWS—not just know service names. Here's your complete guide to passing.
What is DVA-C02?
The Developer Associate certification validates your ability to develop, deploy, and debug cloud-based applications using AWS services. It's designed for software developers with 1+ years of AWS experience.
Exam Details:
- 65 questions (50 scored + 15 unscored)
- 130 minutes
- Passing score: 720/1000
- Cost: $150 USD
- Prerequisites: None (but development experience recommended)
Exam Domains:
- Development with AWS Services (32%)
- Security (26%)
- Deployment (24%)
- Troubleshooting and Optimization (18%)
Who Should Take This Certification?
You're a good fit if you:
- Write code professionally (any language)
- Have deployed applications to production
- Understand APIs, databases, and version control
- Want to build serverless or cloud-native applications
Career paths:
- Cloud Developer ($110k-150k)
- Full-Stack Developer (AWS-focused) ($120k-160k)
- DevOps Engineer ($130k-170k)
Domain 1: Development with AWS Services (32%)
Lambda: The Core of Serverless
Scenario: "Build an API that resizes images uploaded to S3."
Architecture:
S3 Bucket (images-upload)
→ Trigger: S3 Event Notification
→ Lambda Function (resize-image)
- Runtime: Python 3.11
- Memory: 1024 MB (faster execution)
- Timeout: 60 seconds
- Environment Variables: DEST_BUCKET=images-resized
→ S3 Bucket (images-resized)
Lambda Function (Python + Pillow):
import boto3
import os
from PIL import Image
import io
s3 = boto3.client('s3')
def lambda_handler(event, context):
# Get bucket and object key from event
bucket = event['Records'][0]['s3']['bucket']['name']
key = event['Records'][0]['s3']['object']['key']
# Download image
response = s3.get_object(Bucket=bucket, Key=key)
image_data = response['Body'].read()
# Resize image
image = Image.open(io.BytesIO(image_data))
image.thumbnail((800, 600))
# Save to buffer
buffer = io.BytesIO()
image.save(buffer, 'JPEG')
buffer.seek(0)
# Upload to destination bucket
dest_bucket = os.environ['DEST_BUCKET']
s3.put_object(
Bucket=dest_bucket,
Key=f'resized-{key}',
Body=buffer,
ContentType='image/jpeg'
)
return {'statusCode': 200, 'body': 'Image resized'}
Key Lambda Concepts You Must Know:
Execution Role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::images-upload/*"
},
{
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": "arn:aws:s3:::images-resized/*"
},
{
"Effect": "Allow",
"Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
Lambda Layers:
- Package dependencies separately (like Pillow library)
- Reuse across multiple functions
- Max 5 layers per function, 250MB unzipped total
Concurrency:
- Unreserved: Default pool (1000 per region)
- Reserved: Guarantee capacity, prevents throttling
- Provisioned: Pre-warm instances, eliminates cold starts (use for < 1s latency requirements)
Environment Variables:
- Configure settings without code changes
- Can encrypt with KMS
- Max 4KB total
DynamoDB: NoSQL Database
Scenario: "Design a table for a social media app where users post messages and follow each other."
Anti-Pattern (multiple tables):
Users Table (UserId, Name, Email)
Posts Table (PostId, UserId, Content, Timestamp)
Follows Table (FollowerId, FollowedId)
Problems: Multiple queries, slow, expensive
Single-Table Design (recommended):
PK: USER#123 SK: PROFILE → User profile
PK: USER#123 SK: POST#2025-01-15 → User's post
PK: USER#123 SK: FOLLOWS#USER#456 → Following relationship
PK: POST#2025-01-15 SK: POST#2025-01-15 → Post by timestamp (GSI)
Why this works:
- Get user + recent posts: Query PK="USER#123", SK begins_with "POST"
- Get followers: Query PK="USER#123", SK begins_with "FOLLOWS"
- Get recent posts: Query GSI on SK (timestamp)
- One query instead of three → faster, cheaper
DynamoDB Capacity Modes:
On-Demand (pay per request):
- No capacity planning needed
- Good for: unpredictable traffic, new apps, dev/test
- Cost: $1.25 per million reads, $1.25 per million writes
Provisioned:
- Set Read Capacity Units (RCU) and Write Capacity Units (WCU)
- Auto-scaling available
- Good for: predictable traffic, cost optimization
- Cost: $0.00065 per RCU-hour, $0.00065 per WCU-hour
- 55% cheaper than on-demand for steady traffic
DynamoDB Streams:
DynamoDB Table (Order created)
→ Stream (captures INSERT event)
→ Lambda (send confirmation email)
→ SES (email service)
Use cases: Data replication, notifications, aggregations, audit logs
API Gateway: Building APIs
Scenario: "Create a REST API for user management with authentication."
Architecture:
Client → API Gateway
- POST /users (create user)
- GET /users/{id} (get user)
- PUT /users/{id} (update user)
- DELETE /users/{id} (delete user)
↓
Lambda Functions (user-crud)
↓
DynamoDB (users table)
Authentication Options:
IAM Authentication:
- Use AWS credentials (access key + secret)
- Good for: service-to-service, AWS SDK clients
- Client signs requests with SigV4
Lambda Authorizer (Custom):
// Lambda authorizer validates JWT token
exports.handler = async (event) => {
const token = event.authorizationToken;
// Validate token (JWT, OAuth, custom)
const isValid = validateToken(token);
if (isValid) {
return generatePolicy('user123', 'Allow', event.methodArn);
}
return generatePolicy('user123', 'Deny', event.methodArn);
};
Cognito Authorizer:
- Managed user pools, OAuth 2.0
- Good for: mobile apps, web apps
- No Lambda needed for basic auth
API Gateway Features:
Request/Response Transformation:
// Transform request
{
"name": "$input.json('$.userName')",
"timestamp": "$context.requestTime"
}
Caching:
- Enable per-stage caching (300s - 3600s TTL)
- Cache API responses, reduce backend calls
- Pay per GB cached ($0.02/hour per GB)
Throttling:
- Default: 10,000 RPS burst, 5,000 RPS steady
- Set per-method limits for critical endpoints
- Returns 429 Too Many Requests when exceeded
Domain 2: Security (26%)
IAM Policies in Practice
Question: "Lambda needs to read from DynamoDB table 'Orders' and write to S3 bucket 'receipts'."
Inline Policy (bad - hard to manage):
{
"Statement": [{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}]
}
Problem: Too broad, violates least privilege
Correct Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadOrders",
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:Query",
"dynamodb:Scan"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789:table/Orders"
},
{
"Sid": "WriteReceipts",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::receipts/*"
}
]
}
Policy Best Practices:
- Use specific actions (not *)
- Limit resources with ARNs
- Add Sid for clarity
- Use managed policies when possible
Secrets Manager vs Parameter Store
"Store database password securely for Lambda."
Parameter Store (Free Tier):
- 10,000 parameters (Standard)
- No automatic rotation
- Use for: config values, non-sensitive data
- Cost: Free for Standard, $0.05/10k API calls for Advanced
Secrets Manager ($):
- Automatic rotation (Lambda rotates passwords)
- Integration with RDS, Redshift, DocumentDB
- Use for: database credentials, API keys
- Cost: $0.40/secret/month + $0.05/10k API calls
When to use each:
- Config values (API endpoints, feature flags): Parameter Store
- Database passwords, API keys: Secrets Manager
- Frequently rotated secrets: Secrets Manager
KMS Encryption
Scenario: "Encrypt data in S3 and decrypt in Lambda."
S3 Server-Side Encryption:
# Upload with SSE-KMS
s3.put_object(
Bucket='my-bucket',
Key='sensitive-data.txt',
Body='secret content',
ServerSideEncryption='aws:kms',
SSEKMSKeyId='arn:aws:kms:us-east-1:123:key/abc'
)
Lambda needs KMS permissions:
{
"Effect": "Allow",
"Action": ["kms:Decrypt"],
"Resource": "arn:aws:kms:us-east-1:123:key/abc"
}
Domain 3: Deployment (24%)
CI/CD Pipeline with AWS CodePipeline
Scenario: "Automate Lambda deployment from Git push to production."
Pipeline Stages:
1. Source Stage (CodeCommit/GitHub)
- Trigger on push to main branch
2. Build Stage (CodeBuild)
- Run unit tests
- Package Lambda function
- Create deployment artifact (.zip)
3. Deploy Stage (CodeDeploy)
- Deploy to Lambda with alias
- Use canary deployment (10% traffic → 100%)
4. Test Stage (optional)
- Run integration tests
- Manual approval gate
buildspec.yml (CodeBuild):
version: 0.2
phases:
install:
runtime-versions:
python: 3.11
pre_build:
commands:
- pip install -r requirements.txt -t .
- python -m pytest tests/
build:
commands:
- zip -r function.zip .
artifacts:
files:
- function.zip
- appspec.yml
appspec.yml (CodeDeploy):
version: 0.0
Resources:
- MyFunction:
Type: AWS::Lambda::Function
Properties:
Name: my-function
Alias: live
CurrentVersion: 1
TargetVersion: 2
Hooks:
- BeforeAllowTraffic: "PreTrafficHook"
- AfterAllowTraffic: "PostTrafficHook"
Deployment Strategies:
All-at-once:
- Deploy to all instances immediately
- Fastest, but downtime if failure
- Use for: dev/test environments
Canary:
- 10% of traffic → new version
- Wait, monitor errors
- If good → shift 100%
- Use for: production, gradual rollout
Linear:
- Shift traffic in increments (10% every 10 minutes)
- Slower, safest
- Use for: critical applications
CloudFormation: Infrastructure as Code
Deploy complete serverless API:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
MyFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: python3.11
CodeUri: ./function.zip
Events:
ApiEvent:
Type: Api
Properties:
Path: /users
Method: get
RestApiId: !Ref MyApi
Environment:
Variables:
TABLE_NAME: !Ref MyTable
MyTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: users
AttributeDefinitions:
- AttributeName: userId
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
BillingMode: PAY_PER_REQUEST
Deploy:
sam build
sam deploy --guided
Domain 4: Troubleshooting (18%)
CloudWatch Logs Insights
Scenario: "Find all Lambda errors in last hour."
Query:
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 100
Find slow requests:
fields @timestamp, @duration
| filter @duration > 1000
| stats avg(@duration), max(@duration), count(*) by bin(5m)
Track API endpoints:
fields @timestamp, request.path, response.statusCode
| filter response.statusCode >= 400
| stats count(*) by request.path
X-Ray: Distributed Tracing
Enable X-Ray in Lambda:
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch_all
# Patch AWS SDK and HTTP requests
patch_all()
@xray_recorder.capture('process_order')
def process_order(order_id):
# Get order from DynamoDB
order = dynamodb.get_item(TableName='Orders', Key={'id': order_id})
# Process payment
payment = process_payment(order['amount'])
# Send email
send_email(order['email'])
return {'status': 'success'}
X-Ray Shows:
- Total latency: 2.5s
- DynamoDB GetItem: 50ms
- process_payment: 2.2s ⚠️ (bottleneck!)
- send_email: 250ms
Fix: Optimize payment processing or run async
Lambda Troubleshooting
Common Issues:
1. Timeout (max 15 minutes):
Symptoms: Function stops mid-execution
Solution:
- Increase timeout (if needed)
- Or break into multiple functions with Step Functions
- Or move long-running tasks to EC2/ECS
2. Out of Memory:
Symptoms: "Runtime exited with error: signal: killed"
Solution:
- Increase memory allocation
- Profile code to find memory leaks
- Process data in chunks, not all at once
3. Cold Starts:
Symptoms: First request slow (1-5 seconds)
Solutions:
- Use Provisioned Concurrency (costs more)
- Reduce package size
- Move dependencies to Lambda layers
- Keep functions warm (scheduled CloudWatch Event)
4. Throttling:
Symptoms: 429 TooManyRequestsException
Causes:
- Hit concurrent execution limit (1000/region)
- Reserved concurrency set too low
Solutions:
- Increase reserved concurrency
- Request limit increase
- Implement exponential backoff in client
Hands-On Labs (Must Do)
Week 1-2: Serverless Basics
- Create Lambda function triggered by S3 upload
- Build REST API with API Gateway + Lambda + DynamoDB
- Implement Lambda authorizer for authentication
Week 3-4: CI/CD 4. Set up CodeCommit repository, push code 5. Create CodeBuild project with tests 6. Build complete CI/CD pipeline with CodePipeline
Week 5-6: Advanced 7. Implement X-Ray tracing in Lambda 8. Create CloudWatch dashboard and alarms 9. Deploy serverless app with SAM/CloudFormation
Week 7-8: Practice 10. Take practice exams 11. Review weak areas 12. Hands-on debugging scenarios
Practice Questions
Q1: Your Lambda function needs to query DynamoDB and call external API. It times out. What's the BEST solution?
A) Increase Lambda timeout to 15 minutes B) Increase Lambda memory C) Use Step Functions to split into two Lambdas D) Move to EC2
Answer: C - Best practice is to break into separate functions. External API call is the likely bottleneck—handle async.
Q2: Your API Gateway endpoint returns 502 Bad Gateway. What's the likely cause?
A) Lambda function timeout B) API Gateway throttling C) DynamoDB throttling D) IAM permission denied
Answer: A - 502 typically means Lambda timed out or returned malformed response. Check CloudWatch Logs.
Q3: You need to deploy a Lambda function with zero downtime. Which deployment type?
A) All-at-once B) Canary C) Linear D) Blue/Green
Answer: B or C - Both provide zero downtime. Canary is faster (10% → 100%), Linear is safer (gradual increase).
Exam Tips
Before Exam:
- Review Lambda limits: 15min timeout, 10GB memory, 6MB response size
- Memorize DynamoDB capacity calculations
- Know CodeDeploy deployment strategies
- Understand X-Ray, CloudWatch Logs Insights queries
During Exam:
- Watch for "BEST" solution keywords
- Eliminate obviously wrong answers
- Flag uncertain questions, return later
- Code questions test logic, not syntax
Common Traps:
- "Lambda function fails after 15 minutes" → Can't increase timeout, use Step Functions
- "Need sub-second latency" → Use Provisioned Concurrency, not Reserved
- "Debug production Lambda" → X-Ray, not just CloudWatch Logs
Study Resources
Official AWS:
- AWS Certified Developer Study Guide (Nick Alteen)
- AWS Skill Builder: Developer path
- AWS Hands-On Tutorials (free)
Practice Exams:
- Tutorials Dojo DVA-C02 ($15)
- Whizlabs Developer Associate ($20)
- AWS Official Practice Exam ($40)
Hands-On:
- Build real projects (portfolio + exam prep)
- Free Tier: Lambda, DynamoDB, API Gateway
- GitHub: Serverless examples, SAM templates
After Certification
Next steps:
- Build production-ready serverless apps
- Contribute to AWS open-source projects
- Consider DevOps Engineer or Solutions Architect Professional
Keep skills sharp:
- Follow AWS Blog for new features
- Attend AWS re:Invent sessions (YouTube)
- Build side projects with latest AWS services
Ready to practice? Use our AWS Developer Associate Interview Prep with scenario-based questions and hands-on coding challenges.
Vibe Interviews Team
Part of the Vibe Interviews team, dedicated to helping job seekers ace their interviews and land their dream roles.
Ready to Practice Your Interview Skills?
Apply what you've learned with AI-powered mock interviews. Get instant feedback and improve with every session.
Start Practicing Now