Your Data Model Is Your Pricing Model

AWS just made the embedding a column. The interesting consequence is not speed. It is that one data modeling decision, made on day one, now sets your query surface, your latency, and your bill at the same time.

On August 5, 2026, AWS made vector search generally available in Amazon DynamoDB. The announcement led with the numbers you would expect: single-digit millisecond latency, 99 percent plus recall, trillions of vectors, nothing to provision or patch.

Within a day, the commentary had compressed into one sentence: You do not need a vector database anymore.

That reading misses the launch almost entirely. The actual story is buried in the pricing page, and the hardest question it raises is not a vector question at all, which is where I end up at the end.

What shipped

Vector search in DynamoDB is a new index type on an attribute holding an embedding.

You generate the embedding with whatever model you prefer and write it into the item with an ordinary PutItem or UpdateItem. DynamoDB replicates it into the index at 32-bit float precision. No schema migration. That is easy to skim past, and it is most of why adoption will be fast.

You then create the index, declare dimensions, distance function, and any non-vector attributes you want available as filters. It supports up to 4096 dimensions and Euclidean, Cosine, and Dot product distance. The new SearchVectors API takes a query vector, a top K of up to 100, and optional filters.

One detail to get right before you write a threshold anywhere, because the direction flips: for Cosine and Euclidean, lower scores mean more similar, with zero meaning identical, while for dot product higher means more similar. AWS calls Cosine the safe default. Reverse that comparison, and you ship a system that confidently returns the least relevant result available, which is the class of bug that survives a demo and dies in production.

The pipeline you get to delete

Before and after architecture diagram. Before: an application reads and writes to DynamoDB while a sync pipeline of CDC, ETL, or Lambda copies data into a separate vector database, costing a second service, data movement, a sync lag, two sets of IAM permissions, and one more thing on call. After: the application calls SearchVectors against a single DynamoDB table holding operational attributes and a vector index on the same item, with the embedding model the only separate component left.

Before this, if your operational data lived in DynamoDB and you wanted semantic retrieval over it, you copied that data into a dedicated vector store and maintained a synchronization pipeline between the two. AWS says this plainly in the launch post. It is worth reading the full bill for that pipeline rather than nodding past it.

It costs a service to run, data movement, a second set of IAM permissions, a second failure domain, and one more thing on call.

And it introduces a lag, the line item people underestimate, because the embedding always describes a slightly older row than the one your application just read. Most stale-retrieval behavior I have seen traces to that gap, not to the model.

Putting the vector on the same item shrinks that gap. It does not close it: AWS is explicit that vector indexing happens asynchronously after the write is applied, in every Region including the one you wrote to. A delay still separates an acknowledged write from a searchable vector. What changes is whose problem it is, and that is a real win. But it is not the part that decides whether your system is affordable.

The decision that prices everything

Diagram titled One decision, three consequences. A central box reads Vector index partition key, chosen once at index creation, with arrows to three panels. Query surface: every search runs inside a single key value, so global nearest-neighbor across the corpus is not available. Latency: the key distributes vectors across partitions, which keeps latency predictable as the index grows. Unit economics: search bills on bytes processed, so narrowing the partition shrinks the bill.

Here is the part that did not make anyone’s headline.

The vector index takes its own partition key. AWS describes what it does in two separate places, and the two descriptions are usually read separately. Put them side by side and something falls out.

From the launch post: the partition key controls how DynamoDB distributes vectors across partitions, letting the index scale out while maintaining predictable latencies, and each search is scoped to a single partition key value.

From the pricing model: a vector index is billed on three dimensions; the data you write, the data processed when you search, and the data you store, all metered per byte. And when the index defines a partition key, a search is limited to the portion of the index holding that key value.

Read those together. Because search is metered on bytes processed, and the partition key determines how much of the index a search touches, the partition key is also the single largest lever on your search bill.

One decision, taken at index creation before you have real traffic, sets three things:

  • Your query surface. Every search runs inside one value of the key. Global nearest-neighbor across the whole corpus is not available.
  • Your latency. Scoping is what keeps latency predictable as the index grows. The single-digit milliseconds are bought with the scope.
  • Your unit economics. Narrow partitions mean fewer bytes processed per search, and a proportionally smaller bill.

Search is the lever people notice. Writes are the one they find on the invoice. The index meters what you write into it per byte, on top of the write to the table itself, and every update that touches the embedded attribute bills the whole vector again rather than a delta. For a corpus you load once, that rounds to nothing. For anything with churn, it can exceed the search line entirely.

I wrote a small model to find where that lever stops mattering. Because DynamoDB meters search on bytes processed, cost is linear in the fraction of the index a search touches, while S3 Vectors charges a flat fee per query. The two curves cross, and where they cross is the decision.

I am deliberately not quoting dollar figures, because published rates change and mine are placeholders you should replace. The sensitivity is the finding, not the total. That is why the script prints a ratio column next to the dollars: rates rot, ratios do not. The script is below, so run it against live rates and your own access pattern.

This is why “you do not need a vector database anymore” is the wrong takeaway. What AWS shipped is not a general-purpose vector database in a convenient location. It is a tenanted retrieval index, priced to reward small partitions queried hot. If your access pattern is naturally scoped, per customer, per workspace, per agent session, it is close to ideal. If your access pattern is “search everything,” you are about to pay to scan everything, on every query, forever.

The other constraints worth knowing before you commit

Four more limits shape what you can build, none of which appeared in the coverage:

Inline filters are exact match only. Comparison, range, and set-membership operators are, in AWS’s words, not yet available, so “semantically similar documents from the last thirty days” is not expressible in the query. The workaround is bucketing: encode a timestamp as a day key and match it exactly. It works, at the cost of granularity.

Top K caps at 100. Fine for ordinary retrieval, tight if you recall wide then rerank — 100 candidates is not much headroom.

There is no lexical component. No BM25, no scoring on literal word matches, so hybrid retrieval needs a second system for the lexical half, merged in your application.

Responses cap at 16 MB with no paginationA wide projection, large items, and a high top K is what hits it.

None of this makes it a weak service. It makes it a specific one, and knowing the specifics before you commit is the entire job.

Reading the four options by pricing shape

Four cards comparing where embeddings can live on AWS. DynamoDB vector search: vectors on the same item, single-digit millisecond latency, partition-scoped search, priced per byte, rewarding small partitions queried hot. S3 Vectors: cheapest for very large indexes, sub-second latency, fixed fee per million queries. OpenSearch Service: hybrid keyword and vector scoring, you pay for capacity. Aurora or RDS with pgvector: similarity joined to relational data, you pay for the instance.

Read these stores by pricing shape rather than by latency and the choice gets clearer, because the shape tells you what each was built to reward.

DynamoDB vector search has no fixed per-request fee at all. You pay purely for bytes written, processed, and stored, with a one kilobyte minimum. The shape rewards small partitions queried at high rates.

S3 Vectorsgenerally available since December 2025, is the opposite shape. It charges a fixed fee per million queries plus tiered data processing that gets cheaper as the index grows. It holds up to two billion vectors per index, with latency roughly between a hundred milliseconds and a second. The shape rewards large indexes queried at moderate rates.

OpenSearch Service stays the answer when retrieval quality depends on literal terms as much as meaning, and you pay for capacity whether or not anyone queries it. Aurora or RDS with pgvector is the choice when the answer needs a join rather than a neighbor, and you pay for the instance, so retrieval feels free right up until it is the reason you resize.

How I would choose

A four-step decision flow, stopping at the first yes. Does retrieval quality depend on literal terms, range filters, or aggregations as much as semantics: OpenSearch Service. Does the answer need joining to relational data in one transaction: Aurora or RDS with pgvector. Is the index very large with modest query volume and sub-second latency acceptable: S3 Vectors. Does the data already live in DynamoDB on a latency-sensitive path: DynamoDB vector search.

A missing capability is expensive to discover late. Learn in week six that users want recency weighting, and you are not tuning a parameter; you are migrating. So rule out capability constraints first, and let convenience break the tie.

And if you land on DynamoDB, the very next thing to write down, before any code, is the partition key and why. Not the embedding model. Not the chunking strategy. The partition key, because it is the one choice you cannot tune your way out of. Changing it means building a new index and backfilling the corpus behind it.

The question that has nothing to do with vectors

Whichever branch you take, the hardest question is still unanswered, and it is not a vector question at all.

An embedding is derived data, with the properties of a materialized view: computed from a source at a point in time, and wrong from the moment the source changes and it does not.

Storing the vector beside the source shrinks the transport gap. It does not answer the recompute question, and in one way it makes the failure quieter. If the description changes and nothing regenerates the embedding, you have an item whose vector misrepresents its own attributes, from inside your source of truth. Nothing looks broken. There is just a row that retrieves for the wrong queries, indefinitely.

Model changes have the same shape, and almost nobody plans for them on day one. Embeddings from two models are not comparable, so changing your embedding model is a full backfill. Put a model version attribute on the item before you need one.

Before choosing any store, I would answer three questions in writing:

  1. When a source attribute changes, what regenerates its embedding, and how quickly?
  2. What staleness is acceptable, stated as a number rather than as “quickly”?
  3. Who finds out when regeneration silently stops?

Any of the four can serve a system with good answers to those. None can save a system without them.

Run the numbers yourself

Two things I used while writing this, both worth pointing at your own workload rather than trusting mine. Both live in one repo: https://github.com/sirik11/dynamodb-vector-search

A cost model that computes monthly spend under both pricing shapes and sweeps the crossover. Its rates are placeholders; replace them before you quote anything. And a latency benchmark that measures client-observed p50, p95, and p99, with a plan mode that creates nothing and a teardown that removes everything. AWS quotes service-side latency; that benchmark measures round trip. Say which one you are reporting.

# Rates are placeholders. Replace them from the live AWS pricing pages.
DDB_STORAGE_PER_GB_MONTH = 0.25
DDB_SEARCH_PER_GB        = 0.002
S3V_STORAGE_PER_GB_MONTH = 0.06
S3V_PER_MILLION_QUERIES  = 2.50
S3V_PROCESSED_PER_TB     = 0.004   # AWS tiers this per TB, not per GB

GB, TB = 1024 ** 3, 1024 ** 4
SECONDS_PER_MONTH = 30 * 24 * 3600
VECTORS, DIMS, QPS, TOPK, EXTRA_KB = 1_000_000, 1024, 10, 10, 1.0

def monthly(partition_share):
    item_bytes = DIMS * 4 + EXTRA_KB * 1024
    index_gb = VECTORS * item_bytes / GB
    searches = QPS * SECONDS_PER_MONTH

    # The whole argument: the partition key decides how many bytes a search reads.
    scanned = index_gb * GB * partition_share
    per_search = max(scanned + TOPK * item_bytes, 1024)
    ddb = index_gb * DDB_STORAGE_PER_GB_MONTH + searches * per_search / GB * DDB_SEARCH_PER_GB

    # S3 Vectors charges a flat fee per query, so scope barely matters.
    s3v = (index_gb * S3V_STORAGE_PER_GB_MONTH
           + searches / 1_000_000 * S3V_PER_MILLION_QUERIES
           + searches * TOPK * item_bytes / TB * S3V_PROCESSED_PER_TB)
    return ddb, s3v

rows = [(s,) + monthly(s) for s in (0.0001, 0.001, 0.01, 0.1, 1.0)]
base = min(r[1] for r in rows)
print(f"{'index touched':>14}{'DynamoDB':>12}{'S3 Vectors':>12}{'vs best':>10}")
for share, ddb, s3v in rows:
    print(f"{share:>13.2%}{ddb:>12,.0f}{s3v:>12,.0f}{ddb/base:>9,.0f}x")

I would rather see ten engineers publish their own measured numbers than read one more post quoting the same press release. If you run either script, I would like to see what you get.

What I would watch next

Range conditions on inline filters. If exact-match filtering grows range support, a meaningful share of today’s OpenSearch cases collapse back into DynamoDB.

A lexical component. Hybrid scoring in one call is currently the clearest reason to stay on OpenSearch, so it is where I would expect pressure next.

The real shift is not that a vector database became unnecessary. It is that “where do the embeddings live” stopped being an infrastructure question and went back to being a data modeling question, which is where it always belonged.

The embedding is a column now. The partition key is the product. Pick it on purpose.