# Monthly DynamoDB capacity and cost review dashboard

> Open one screen each month to see which DynamoDB tables waste money on capacity nobody uses and which are quietly throttling users, with dollar estimates.

- Workflow type: app
- Services: Amazon DynamoDB, Amazon CloudWatch, Slack Bot
- Categories: Engineering, Finance
- Published: 2026-08-14

## What it does

- Lists every table in your AWS region with its capacity settings, item count and stored size, side by side with what it actually used over the last 30 days
- Flags two problems in plain language: tables paying for capacity they never touch, and tables slowing users down because they need more headroom
- Puts a rough monthly dollar figure on each problem, so the shortlist is easy to argue about in a planning meeting instead of easy to ignore
- Opens any table for a usage chart, peak versus average utilization, and one clear recommendation: keep it, resize it, or switch how it is billed
- Records your decision per table so next month shows what you already decided and when, and shares the shortlist to your engineering channel in Slack

## What you'll need

- An AWS account with read access to your DynamoDB tables and to your monitoring data
- The AWS region your tables live in, for example us-east-1
- A small DynamoDB table to hold review decisions. The app shows you exactly what to create the first time you open it
- A Slack workspace, only if you want to share the shortlist with your team

## Prompt

Build me a capacity and cost review dashboard that I open at the start of each month to decide which Amazon DynamoDB tables are wasting money and which are quietly throttling users. This is a review surface I work in, not an alerting workflow: nothing runs on a schedule, I open it, read the shortlist, decide, and move on. Every number on screen has to be readable by a manager, not just an engineer.

The landing view is a sortable fleet table with one row per DynamoDB table. Use List Tables to enumerate every table in the connected region, following its pagination cursor so accounts with many tables are complete. Then call Describe Table on each one for capacity mode (provisioned or on demand), provisioned read and write capacity units, item count, and stored size. Format these for a human: size as GB or MB rather than raw bytes, item counts with thousands separators, and capacity mode as words rather than API enum values. Note in the UI that item count and size are values DynamoDB refreshes roughly every six hours, so they are approximate.

Next to each table, show what it actually used over the last 30 days, pulled from Amazon CloudWatch. Call List Metrics first against the AWS/DynamoDB namespace to discover which tables actually report metrics. This matters: a table that reports nothing must be shown as "no usage reported" and never as zero usage, because those mean completely different things and only one of them is safe to act on. Then for each reporting table call Get Metric Statistics with the TableName dimension for ConsumedReadCapacityUnits and ConsumedWriteCapacityUnits, and for throttling counts via ReadThrottleEvents and WriteThrottleEvents.

Get the statistics call right, because everything downstream depends on it. Use the Sum statistic with a 3600 second period over the 30 day window, which yields 720 datapoints and stays well inside the per-request datapoint limit while remaining available in CloudWatch retention. Consumed capacity is reported as a sum per period, so divide each datapoint by the period in seconds to get average units per second. That per second figure is the only number that compares directly against provisioned capacity units, so do the conversion once, centrally, and use it everywhere.

Score each table and flag two problems in plain language. A table is overprovisioned when sustained usage sits far below what we pay for: average consumed units per second are a small fraction of provisioned units and the peak is still comfortably underneath. A table is throttling when there is a meaningful count of throttled requests across the window, meaning it needs more headroom or a switch to on demand. Most tables will be neither, and that is a fine and expected outcome. Sort the fleet worst first by estimated monthly dollars at stake, and let me re-sort by any column.

Bake in the widely used rule of thumb that provisioned capacity tends to beat on demand once sustained utilization is meaningfully high. Use a configurable crossover of 18 percent sustained utilization of provisioned capacity: below that, on demand is usually the cheaper billing mode, and above it provisioned can run roughly 80 percent cheaper than on demand at continuous usage. Show the threshold on screen with a one line explanation of what it means, and let me change it, because the right number depends on how much headroom we want for spikes. Apply the comparison in both directions, so an on demand table with heavy steady traffic gets flagged as a candidate for provisioned just as readily as an overprovisioned table gets flagged for downsizing.

Put a rough monthly dollar estimate on every flag so the list is arguable rather than ignorable. Keep all unit prices in one editable settings block, defaulting to published us-east-1 rates: 0.00013 dollars per read capacity unit hour and 0.00065 dollars per write capacity unit hour for provisioned, 0.25 dollars per million read request units and 1.25 dollars per million write request units for on demand, and 0.25 dollars per GB month for storage. For an overprovisioned table, waste is the unused capacity units, meaning provisioned units minus what observed usage plus a safety headroom actually requires, multiplied by the hourly rate and by 730 hours. For a throttling or on demand table, estimate what the alternative billing mode would cost at the observed volume and show it beside what it costs today. Label every figure clearly as an estimate, display the rates and region used to produce it, and round to whole dollars.

Clicking a table opens a detail view. Show a usage over time chart of read and write consumption across the 30 days with the provisioned capacity drawn as a reference line, so the gap between what we pay for and what we use is visible at a glance. Show peak versus average utilization as percentages of provisioned capacity, throttling events over the same timeline so I can see whether throttling is constant or a single bad afternoon, and one recommendation: keep as is, resize provisioned capacity, or switch capacity mode. When the recommendation is a resize, suggest a specific number and show the working. Underneath, write a short plain-language paragraph explaining why, in the register of "this table is using 4 percent of what you pay for, and has never gone above 11 percent".

Let me record a decision per table from the detail view: keep, resize, switch mode, or revisit next month, plus an optional free-text note. Save it with Put Item into a small DynamoDB review table, default name dynamodb-capacity-reviews and configurable in settings, with partition key TableName and sort key ReviewedAt holding an ISO timestamp. Store the decision, the note, who decided, and the key numbers as they stood at decision time, so a later reader can see what the decision was based on rather than just what it was. On load, read decisions back with Scan and hydrate the fleet table with the last decision and its date, visually de-emphasizing rows already decided this cycle so my attention goes to what is new.

If the review table does not exist, do not fail silently or show a broken screen. Detect the resource-not-found error and show a short setup panel explaining what to create and with which key schema, and optionally offer a one-click Create Table that provisions it. The rest of the dashboard must still work fully in read-only mode while that table is missing, since the review data is an enhancement and the analysis stands on its own.

Give me a share button that posts the current shortlist of problem tables to our engineering channel using Slack Bot Send a Message. Populate a channel picker with List Channels and let me preview and edit the message before it sends. Write it to be readable on a phone: a one line headline with the total estimated monthly waste, then a short list of the flagged tables with the flag and dollar figure for each, then a closing line noting how many are already decided. Do not paste the whole fleet into Slack, only the shortlist that needs a human decision.

Throughout, favour manager-readable phrasing over raw telemetry. Prefer "using 4 percent of what you pay for" to a bare capacity unit count, put a dollar figure next to every recommendation, and write flags as sentences rather than status codes. Keep the underlying units and datapoints available but visually secondary, so an engineer can audit any number without that detail being the first thing anyone sees.

Two practical notes on making it feel fast and sturdy. Metrics for a whole fleet is a lot of calls, so fetch the table metadata first and render the fleet immediately, then fill usage and dollar columns in progressively rather than blocking the page on the slowest call. Cache the month's pull so reopening the dashboard is instant, with a visible manual refresh and a timestamp showing how fresh the data is. If CloudWatch or DynamoDB fails for one table, mark that single row unavailable with the reason and keep every other row working, because a partial fleet review is still useful and a blank screen is not.

## How to customize

- Change the review window from the default 30 days, or the point at which a table counts as overprovisioned
- Adjust the sustained utilization threshold that decides when reserved capacity beats pay-per-request billing
- Update the per-unit prices to match your region so the dollar estimates line up with your real bill
- Choose which Slack channel the shortlist posts to, and edit the message before it sends

## FAQ

### Do I need to be an engineer to understand this?

No. Every table gets a plain-language flag and a dollar estimate, so you can see which tables are wasting money and which are struggling without knowing anything about capacity units. The raw technical numbers are still there if an engineer wants to check the math.

### Will this change anything in my AWS account?

No. The dashboard only reads your table settings and usage history. The only things it writes are the decisions you choose to record and the Slack message you choose to send. It never resizes a table or changes how one is billed, so you stay in control of the actual change.

### Why does it look at 30 days?

One month is long enough to cover weekly traffic cycles and month-end peaks, so a table that looks quiet on a Tuesday does not get flagged as wasteful when it is busy every Friday. It is also the window most teams use before changing capacity. You can shorten or lengthen it.

### What happens to tables with no usage data?

They are shown as not reporting usage rather than as zero usage, which matters because those are very different things. A table that reports nothing may be genuinely unused, or may simply be new. The app keeps the distinction visible so you do not act on a blank.

### Does it work if my tables are on pay-per-request billing?

Yes. Those tables appear too, and if one has enough steady traffic that reserving capacity would be meaningfully cheaper, the app says so and estimates the difference. The comparison runs in both directions rather than only flagging overprovisioning.

### Can I see what we decided last month?

Yes. Every decision is saved with a timestamp and an optional note, so when you open the dashboard next month each table shows what was decided and when. Tables you have already reviewed this cycle are de-emphasized so you can focus on what is new.

Use this prompt in General Input: https://www.generalinput.com/prompts/monthly-dynamodb-capacity-and-cost-review-dashboard