Perplexity Left DynamoDB for CobbleDB: When Should You?
Perplexity built its own key-value store because DynamoDB's read path and bill stopped fitting 50 KB search items. Here is the checklist for when leaving is justified.
Key takeaways
- Perplexity built its own key-value store because DynamoDB's read path and bill stopped fitting 50 KB search items.
- Here is the checklist for when leaving is justified.
On this page
Almost nobody should copy Perplexity, but almost everybody should run the same audit. According to The New Stack's report, Perplexity replaced DynamoDB on its search read path with CobbleDB, a roughly 40,000-line Rust key-value store, because it was paying too much and could not control how reads behaved. The lesson is not "build your own database". It is that an exit is only defensible when you can name the cost driver and the missing control in one sentence each.
What Perplexity actually reported#
The numbers are worth stating precisely, because the caveats matter as much as the headline. A single Search API call fetches 100 to 120 page keys in batches of 10 to 20, and each item averages about 50 KB. Perplexity measured median batch-read latency at 5.6 ms on CobbleDB versus 31.4 ms on DynamoDB, and p99 fell from 123 ms to 24.2 ms. Its cost model puts CobbleDB at least 20% below DynamoDB across the commitment options it evaluated.
Now the fine print, which the article itself flags. The two latency figures were not measured side by side on identical traffic: DynamoDB's were recorded before the cutover, CobbleDB's after. The 20% estimate excludes the engineering cost of running the thing. Two engineers, hundreds of coding agents, eight weeks to build. The agents did not run production; the engineers did.
The read path was the real complaint#
The article says DynamoDB gave Perplexity little say over how reads were handled, so one slow replica could hold up an entire batch. CobbleDB's router can try another replica when one is slow, keeps reads inside the same availability zone when possible, and lets replicas fall behind and catch up independently.
That is a tail-latency argument. When one request fans out into 100-plus keys, your latency is the slowest of many lookups, so p99 of the store becomes p50 of your API. If your workload is single-key lookups by primary key, this complaint does not apply to you, and the exit case loses half its weight immediately.
Check the bill against the item size first#
Large items are where DynamoDB's cost model bites hardest. A read unit covers up to 4 KB, so by our arithmetic a 50 KB item costs 13 units for a strongly consistent read and about 6.5 for an eventually consistent one, before you multiply by 100-plus keys per call.
Before anything else, measure what your table actually consumes. This pulls seven days of consumed read and write units from CloudWatch and turns them into a monthly figure. Set the two price variables yourself from the AWS DynamoDB pricing page for your region and mode; we deliberately do not hard-code numbers that change.
#!/usr/bin/env bash
# ddb-cost-estimate.sh <table-name> ; needs aws CLI v2 and awk
set -euo pipefail
TABLE="$1"
# USD per million units, copied from the AWS pricing page for your region/mode
RRU_PER_M="${RRU_PER_M:?set price per million read units}"
WRU_PER_M="${WRU_PER_M:?set price per million write units}"
END=$(date -u +%Y-%m-%dT%H:%M:%SZ)
START=$(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)
sum_metric() {
aws cloudwatch get-metric-statistics --namespace AWS/DynamoDB \
--metric-name "$1" --dimensions Name=TableName,Value="$TABLE" \
--start-time "$START" --end-time "$END" --period 86400 \
--statistics Sum --query 'Datapoints[].Sum' --output text |
tr '\t' '\n' | awk '{s+=$1} END {printf "%.0f", s}'
}
R=$(sum_metric ConsumedReadCapacityUnits)
W=$(sum_metric ConsumedWriteCapacityUnits)
awk -v r="$R" -v w="$W" -v rp="$RRU_PER_M" -v wp="$WRU_PER_M" 'BEGIN {
printf "7d reads: %d units, writes: %d units\n", r, w
printf "Estimated monthly: $%.2f (scaled x30/7)\n", (r/1e6*rp + w/1e6*wp) * 30/7
}'
This estimate fits on-demand tables, where consumed units map directly to billed units. On a provisioned table, you pay for what you provisioned, so compare against ProvisionedReadCapacityUnits instead; the gap between the two is your waste.
Rule out the cheaper fixes before you write Rust#
Leaving DynamoDB is the last item on the list, not the first. Work down in this order:
On-demand versus provisioned. A steady, predictable workload on on-demand pays a premium for flexibility it never uses. Switching to provisioned with autoscaling, or reserved capacity, is a config change, not a migration.
Hot partitions. Throttling with low average utilization usually means a skewed key, not a bad database. Fixing the key design costs a week; replacing the store costs a year. Our notes on database sharding choices we wish we made earlier cover the same skew problem from the other side.
Caching. If reads are repetitive, DAX or a plain in-process or Redis cache in front of the table can cut consumed units sharply. Perplexity's batch pattern across a huge corpus probably caches poorly, which is part of why its case is real. Yours may not be.
Item shape. If items are large because you store blobs, move the blobs to S3 and keep pointers in the table. Perplexity did a version of this at scale by separating durable document storage from the serving store.
Migration risk is the cost nobody puts in the spreadsheet#
Perplexity's 20% figure omits maintenance, on-call, and the day a replica corrupts. Add that number yourself. For most teams, 20% of a modest DynamoDB bill is less than one engineer's salary, and the arithmetic ends there.
If a different managed store fits the access pattern better, that is a far cheaper exit than self-hosting. Read-heavy, globally distributed workloads might suit something like the ones in Turso vs Cloudflare D1, and a tracked bill is easier to defend with the right tooling from our best FinOps tools roundup.
The decision, concretely#
- Is the bill high mainly because of large items or steady bulk reads? Measure with the script above, then shrink items or move blobs to S3 before considering anything else.
- Do you see tail latency from fan-out batch reads you cannot steer? That is the one complaint that a managed key-value store may genuinely not fix; test a replica-aware alternative.
- Is the workload steady and single-key? Stay. Provisioned capacity, reservations, and a cache will beat any migration.
- Do you lack a team that can own a datastore on call? Stay, whatever the savings estimate says.
The call we'd make#
Stay on DynamoDB unless you can show, with your own CloudWatch numbers, that item size and fan-out reads drive the bill and the tail. Fix keys, capacity mode, and caching first, then look at a different managed store. Build your own only if you have Perplexity's scale, its read-path grievance, and engineers you are willing to page.
Get the DevOps Troubleshooting Cheat Sheet
Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.
AI Agents and Kubernetes Remediation: Write Access Is the Easy Part
Handing an agent kubectl is a five-minute job. Proving the fix worked and did no harm is the real work, and it belongs in the wrapper, not the prompt.
CERN Left Red Hat for Debian: The CPU Baseline Lesson
CERN is moving accelerator control computers to Debian because RHEL raised its minimum CPU level. Check your own fleet's x86-64-vN support before the next OS upgrade does it for you.
More from Infrastructure
Explore more articles in this category
The Terraform Lock File Is Code: Review It Before You Init
A DPRK-linked group is mailing DevOps candidates Terraform take-home repos whose lock file points at a fake registry. terraform init then runs the attacker's provider.
Redis vs Memcached: Choosing a Cache in 2026
Both are fast in-memory stores, and both get picked by habit more than by requirements. Here is what actually differs and when each one is the right call.
Vault vs AWS Secrets Manager vs Doppler: Choosing a Secrets Tool
One is a full secrets platform, one is AWS-native and hands-off, and one is built for developer workflow. Picking by feature list alone misses the real tradeoff.
You might have missed
Evergreen posts worth revisiting.