AWS CDK Cost Estimation: Shift FinOps Left Into Pull Requests
Quick summary: Most FinOps reviews happen weeks after infrastructure ships, when the bill arrives. CDK cost estimation flips that — synthesize the stack, walk the resource graph, hit the AWS Pricing API per resource, and post a monthly-cost diff on every pull request. The cost feedback loop drops from weeks to minutes; the failure modes (request volume, token usage, data transfer) are documented up front.
Key Takeaways
- Most FinOps reviews happen weeks after infrastructure ships, when the bill arrives
- CDK cost estimation flips that — synthesize the stack, walk the resource graph, hit the AWS Pricing API per resource, and post a monthly-cost diff on every pull request
- The reviewer sees "this change adds $850/month at baseline" before merge, not "the bill went up by $850" three weeks after deploy
- For the service-specific pricing details that feed into estimation, see the other posts in our AWS pricing series
- The Estimation Pipeline The pattern that works across CDK projects: 1
Table of Contents
The standard FinOps loop is: someone ships infrastructure, the bill arrives 3–4 weeks later, the FinOps team flags the variance, the engineering team reviews the change history, the offending change is identified, the fix is scheduled. The loop closes in weeks, sometimes months. CDK cost estimation closes that loop in minutes — synthesize the stack in CI, walk the resource graph, query the AWS Pricing API per resource, post the estimated monthly cost as a comment on the pull request. The reviewer sees “this change adds $850/month at baseline” before merge, not “the bill went up by $850” three weeks after deploy.
This post is a methodology guide rather than a service pricing breakdown. For the service-specific pricing details that feed into estimation, see the other posts in our AWS pricing series.
What CDK Cost Estimation Can and Cannot Compute
The bill split that determines what estimation produces meaningful numbers for:
Resource cost categories — what estimation handles well
Prices in any
Fixed-and-predictable lines: estimation excels. Volume-driven lines: estimation needs explicit assumptions.
| Dimension | Unit price | Example workload | Monthly cost |
|---|---|---|---|
| Per-hour fixed resources Easiest category; SKU × hours × region | EC2 instance hours, RDS instance hours, NAT Gateway, Transit Gateway, MQ broker hours, ELB hours | CDK creates an EC2 t4g.large | Exact estimate |
| Per-GB-month storage Provisioned storage is computable | EBS provisioned, RDS storage, EFS provisioned mode | 500 GB gp3 | Exact estimate |
| Per-resource flat fee Direct count × rate | KMS keys ($1/month), CloudWatch dashboards ($3/month), VPC Lattice service ($18/month) | 50 KMS keys | Exact estimate |
| Request-volume lines Cannot estimate without expected volume | Lambda invocations, API Gateway calls, DynamoDB on-demand, SQS requests, KMS requests | Lambda function | Needs assumption |
| Data-transfer lines Workload-dependent | NAT Gateway processing, CloudFront egress, inter-AZ transfer | NAT in a VPC | Needs assumption |
| Token / inference-volume lines Largest variance in modern stacks | Bedrock model invocations, SageMaker inference | Bedrock-enabled stack | Needs assumption |
| Logs / metrics ingest Dependent on workload chattiness | CloudWatch Logs ingestion ($0.50/GB), custom metrics | Application emitting logs | Needs assumption |
Per-hour fixed resources
Exact estimateEasiest category; SKU × hours × region
- Unit price
- EC2 instance hours, RDS instance hours, NAT Gateway, Transit Gateway, MQ broker hours, ELB hours
- Example workload
- CDK creates an EC2 t4g.large
Per-GB-month storage
Exact estimateProvisioned storage is computable
- Unit price
- EBS provisioned, RDS storage, EFS provisioned mode
- Example workload
- 500 GB gp3
Per-resource flat fee
Exact estimateDirect count × rate
- Unit price
- KMS keys ($1/month), CloudWatch dashboards ($3/month), VPC Lattice service ($18/month)
- Example workload
- 50 KMS keys
Request-volume lines
Needs assumptionCannot estimate without expected volume
- Unit price
- Lambda invocations, API Gateway calls, DynamoDB on-demand, SQS requests, KMS requests
- Example workload
- Lambda function
Data-transfer lines
Needs assumptionWorkload-dependent
- Unit price
- NAT Gateway processing, CloudFront egress, inter-AZ transfer
- Example workload
- NAT in a VPC
Token / inference-volume lines
Needs assumptionLargest variance in modern stacks
- Unit price
- Bedrock model invocations, SageMaker inference
- Example workload
- Bedrock-enabled stack
Logs / metrics ingest
Needs assumptionDependent on workload chattiness
- Unit price
- CloudWatch Logs ingestion ($0.50/GB), custom metrics
- Example workload
- Application emitting logs
Estimation produces a 'baseline run-rate' — what the stack costs at zero traffic. Production cost = baseline + traffic-driven lines.
The Estimation Pipeline
The pattern that works across CDK projects:
- Synthesize.
cdk synthproduces the CloudFormation template. Estimation runs against the synthesized template, not against the CDK source — this means it works regardless of how the CDK is structured. - Walk the resource graph. Parse the template, enumerate every resource by
Type, extract the relevant pricing dimensions (instance type for EC2, allocated storage for EBS, etc.). - Query the Pricing API. For each resource, call the AWS Pricing API (or use a cached result) to get the per-unit rate. Multiply by hours-per-month (730 hours by convention) for per-hour resources.
- Apply assumptions. For volume-driven lines, look up CDK-app-declared assumptions (e.g.,
expected.lambda.invocations.monthlyin the CDK context). - Aggregate. Sum the per-resource costs, group by service or by stack section, produce a JSON output.
- Post. Format the JSON as a markdown comment on the pull request showing the cost diff against the main branch.
The pipeline runs in CI alongside the existing cdk synth and cdk diff steps. Total added time: 30–60 seconds for a typical stack with a few hundred resources, assuming pricing API responses are cached.
The Pricing API Cache
The AWS Pricing API is free but rate-limited and adds latency. For CI/CD integration, caching is essential:
The PR Comment Pattern
The output that drives behavior change is the PR comment. A useful comment includes:
- Baseline cost change: ”+$X/month at baseline” (positive or negative).
- Per-service breakdown: which AWS services contribute to the delta.
- High-leverage line items: any new line >$100/month flagged with a callout.
- Volume assumptions used: explicit list so reviewers can verify the assumptions.
- Link to fuller report: longer-form breakdown for reviewers who want depth.
Format the comment with collapsible sections so it does not dominate the PR page. The reviewer sees the summary; they expand for detail when needed.
Cost Assumptions as First-Class Documentation
For volume-driven lines, the CDK app declares expected operating envelope:
// CDK context (cdk.json or per-stack)
{
"costAssumptions": {
"lambda.invocations.monthly": 5000000,
"lambda.avgDurationMs": 250,
"dynamodb.readUnitsHourly": 100,
"dynamodb.writeUnitsHourly": 50,
"natGateway.dataProcessedGB": 200,
"bedrock.claudeHaiku.inputTokensMonthly": 50000000,
"cloudwatchLogs.ingestedGB": 100
}
}
The estimation tool reads these and applies them to the relevant resources. Two benefits beyond cost numbers:
- The assumptions become documentation. A reviewer can see the team’s expected operating envelope alongside the code.
- The assumptions become testable. Production CloudWatch metrics can be compared against the declared assumptions; significant variance is itself a signal worth investigating.
What Estimation Catches That Code Review Often Misses
The estimator surfaces patterns that are visible in code but easy to miss in review:
- NAT Gateways added without a corresponding VPC endpoint — the estimator flags “$98.55/month for the 3-AZ NAT setup” and the reviewer remembers to ask whether the workload accesses S3/DynamoDB (in which case Gateway Endpoints would be free).
- Multi-AZ RDS where single-AZ would do — the estimator shows the doubled instance cost; the reviewer asks whether the workload’s availability requirement actually warrants Multi-AZ.
- CloudWatch dashboards proliferating — the estimator catches each $3/month dashboard.
- Interface VPC Endpoints across all AZs for a low-volume service — the estimator flags the $21.60/month/service rate and the reviewer asks whether the service traffic justifies it.
- Bedrock Provisioned Throughput before need — the estimator shows the monthly commitment and the reviewer asks whether on-demand would suffice.
When Cost Estimation Won’t Help
Three categories of cost decisions estimation can’t easily surface:
- Spot vs On-Demand decisions — estimation reports the on-demand price by default; the actual cost depends on Spot capacity availability and interruption tolerance. Manual decision.
- Reserved Instance / Savings Plan opportunities — estimation reports the on-demand baseline; the optimization is at the purchase layer rather than the deployment layer.
- Multi-region or DR cost decisions — estimation reports per-stack cost; the question of “should this be multi-region?” is a business decision the estimator can’t make.
The estimator’s value is the fast feedback on changes you ship; the strategic cost decisions (purchase commitments, multi-region posture) happen elsewhere.
When to Build vs Buy Estimation Tooling
Build a custom estimator for teams with strong CDK conventions; use off-the-shelf for fast adoption on diverse stacks.
Use when
- Build custom: team has well-defined CDK conventions and specific assumption schemas
- Build custom: estimation needs to integrate with internal cost-attribution systems (cost-center tags, ownership metadata)
- Build custom: stack uses many non-standard or newly-released AWS services where off-the-shelf tools may lag
- Buy off-the-shelf: team needs estimation immediately and lacks capacity to build
- Buy off-the-shelf: stack uses common AWS services where the off-the-shelf coverage is good
- Hybrid: use off-the-shelf for the common-service portion, add custom logic for workload-specific assumptions
Avoid when
- Either approach without PR-comment integration — the feedback loop is the whole point
- Custom estimation without a pricing cache — CI runs become slow and waste API quota
- Pure-CDK estimation in a multi-IaC environment — the team needs estimation across CloudFormation, Terraform, and CDK simultaneously
- Estimation as a replacement for AWS Budgets — they are complementary, not alternatives
The principle matters more than the tool. Get cost feedback into PRs; the specific implementation can evolve.
A 30-Day Rollout Plan
Week 1 — Build the estimator skeleton. Pick the pipeline (custom + Pricing API, or off-the-shelf). Get it running locally against one stack. Validate that the baseline numbers match expected (compare against the Pricing Calculator manually).
Week 2 — Add to CI for one repo. Wire into the CI pipeline that runs cdk synth. Post the output as a PR comment. Iterate on the comment format until reviewers find it useful.
Week 3 — Add cost assumptions. For request-volume and data-transfer lines, define the assumption schema. Document expected monthly volumes for the major workloads. Refine the estimator to use the assumptions.
Week 4 — Roll out across repos. Apply the same CI integration to all CDK repos. Document the assumption schema as the team’s “expected operating envelope” convention. Tie the assumptions to the existing FinOps reporting.
What This Post Doesn’t Cover
- Terraform cost estimation specifically — the principles are identical; tooling is more mature for Terraform (Infracost is the canonical example).
- AWS Application Composer + Cost view — useful for visual design-time estimation; not built for CI/CD.
- Cost allocation tagging — orthogonal concern that affects post-deploy cost attribution rather than pre-deploy estimation.
- Multi-account cost forecasting — a larger discipline that uses estimation as one input among many.
If You Only Do One Thing This Week
Pick your highest-traffic CDK repo, write a 100-line script that runs after cdk synth, parses the generated CloudFormation, looks up the per-hour rate for every EC2/RDS/NAT/MQ/Lattice resource via the AWS Pricing API, and prints the monthly cost estimate. Don’t worry about volume-driven lines yet. Don’t worry about the PR comment integration yet. Just get a number that estimates the baseline run-rate of your largest stack. The exercise itself surfaces the resource types that drive your bill — and once you have the number, every subsequent change becomes “did this make the baseline better or worse?”
For the broader FinOps context — when CDK cost estimation fits into the FinOps practice as a whole — our FinOps on AWS guide covers the operating-model side.
AWS Cloud Architect & AI Expert
AWS-certified cloud architect and AI expert with deep expertise in cloud migrations, cost optimization, and generative AI on AWS.