DynamoDB Vector Search: How to Create a Vector Index and Use SearchVectors (CLI and Python), Pricing per GB, the Tenant-Isolation Trap, and Why DynamoDB Local Ignores It
Yes, DynamoDB supports vector search. Since August 5, 2026, you can add a vector index to a table and find the items most similar to a query vector with the new SearchVectors API, without a separate vector database. You store embeddings (from a model such as Amazon Titan Text Embeddings) as a list of numbers on each item, define the index with its dimensions (up to 4,096) and a distance function (COSINE, EUCLIDEAN or DOT_PRODUCT), and search with up to 100 results per call. It is billed by the byte, not by the hour: in US East, $0.002 per GB of vector data searched and $0.52 per GB of vector writes, with a 1 KB minimum per request, on on-demand tables only. Two things catch people out. First, the per-tenant partition key that makes searches fast is not a security boundary: DynamoDB's fine-grained access control does not apply to SearchVectors, so anyone allowed to search the index can search every tenant. Second, DynamoDB Local does not support it: in our test, it accepted a table with a vector index, quietly left the index out, and answered SearchVectors with "An unknown operation was requested." This guide covers setup in the CLI and Python, pricing, limits, security and every trap we found.
Jake's two shops have 2,000 repair notes between them, written by six technicians who all describe the same fault differently. "Screen flickers", "display flashing", "LCD blinking after a drop." Ethan wanted a search box that finds the right past repair whatever words the technician uses. "Can't the database just do that now?" Jake asked. "As of August, ours can," Ethan said. "If I set up two things that the announcement didn't mention."
New to vectors? An embedding is a list of numbers that an AI model produces from a piece of text (or an image) so that similar meanings land close together. "Screen flickers" and "display flashing" get similar lists even though they share no words. A vector search finds the stored embeddings closest to the embedding of your question. DynamoDB, AWS's serverless key-value database, can now do that search itself; our plain-English DynamoDB guide covers the basics of tables and items. DynamoDB does not create embeddings; you get them from a model, for example on Amazon Bedrock.
What DynamoDB vector search is, and what it supports
A vector index is a third kind of DynamoDB index, alongside global and local secondary indexes. Instead of exact-match and range queries, it does approximate nearest neighbor (ANN) search: it finds the items whose vectors are most similar to yours, ranked by a similarity score, without comparing your vector with every stored one. DynamoDB keeps the index in sync with the table automatically, as it does for other indexes.
| Item | DynamoDB vector index (October 2026) |
|---|---|
| Available since | August 5, 2026, in all commercial Regions, AWS GovCloud (US) and the China Regions |
| API | SearchVectors to search; CreateTable (VectorIndexes) and UpdateTable (VectorIndexUpdates) to manage |
| Per table | Up to 5 vector indexes |
| Dimensions | Up to 4,096, stored as 32-bit floats |
| Distance functions | COSINE, EUCLIDEAN, DOT_PRODUCT |
| Results | TopK from 1 to 100; response up to 16 MB, no pagination |
| Filtering | One partition key (HASH) and up to 18 inline filters, equality (=) only |
| Capacity mode | On-demand only; the table must be on-demand too |
| Not supported | Query, Scan or PartiQL on the index; DAX; fine-grained access control; DynamoDB Local |
Good uses: semantic search over product descriptions or support articles, retrieval for RAG (giving a language model the right documents), "similar items" recommendations, memory for AI agents, and spotting unusual events by comparing them with normal ones. "So it's a GSI that understands meaning," Jake said. "A GSI that understands closeness," Ethan said. "The meaning comes from the model that made the numbers."
Choosing a distance function (you cannot change it later)
| Function | Score | Best for |
|---|---|---|
| COSINE | 0 (same direction) to 2 (opposite); lower is more similar | Text embeddings, semantic search, RAG; the safe default |
| EUCLIDEAN | Straight-line distance; lower is more similar | Image or audio embeddings, near-duplicate detection, clustering |
| DOT_PRODUCT | Higher is more similar; can be negative | Models that recommend it; ranking where vector length carries meaning |
Watch the direction: a "score" of 0.02 is a near-perfect match under COSINE and a poor one under DOT_PRODUCT. Code that sorts or thresholds scores must know which function the index uses. If you normalize your embeddings to unit length (Titan's "normalize": true does this), DOT_PRODUCT ranks results the same way as COSINE. The dimensions, the distance function, the partition key and the inline filters are all fixed when you create the index; to change any of them, create a new index and switch to it.
How to set up DynamoDB vector search with the AWS CLI
- Choose the embedding model and its dimensions. Amazon Titan Text Embeddings V2 (
amazon.titan-embed-text-v2:0) returns 1,024 dimensions by default; other common sizes are 384, 768, 1,536 and 3,072. Use the same model for stored vectors and for queries. - Use an on-demand table. Create it with
--billing-mode PAY_PER_REQUEST, or switch an existing provisioned table to on-demand before adding the index. - Create the table with a vector index. Here the index is partitioned by shop, so each search looks only at one shop's notes:
Every attribute you name inaws dynamodb create-table \ --table-name repair-notes \ --attribute-definitions AttributeName=note_id,AttributeType=S AttributeName=shop,AttributeType=S \ --key-schema AttributeName=note_id,KeyType=HASH \ --billing-mode PAY_PER_REQUEST \ --vector-indexes '[{ "IndexName": "note-embedding", "VectorAttribute": {"AttributeName": "embedding"}, "SearchSchema": [{"AttributeName": "shop", "SearchSchemaElementType": "HASH"}], "Projection": {"ProjectionType": "INCLUDE", "NonKeyAttributes": ["text"]}, "Dimensions": 1024, "DistanceFunction": "COSINE" }]'SearchSchemamust also appear in--attribute-definitions. - Or add it to an existing table:
aws dynamodb update-table --table-name repair-notes \ --vector-index-updates '[{"Create": { "IndexName": "note-embedding-v2", "VectorAttribute": {"AttributeName": "embedding"}, "Projection": {"ProjectionType": "KEYS_ONLY"}, "Dimensions": 1024, "DistanceFunction": "COSINE"}}]' - Wait until it is really ready.
describe-tableshowsIndexStatusCREATING, thenCREATINGwithBackfilling: truewhile it loads existing items, thenACTIVE. Even afterACTIVE, the separate search endpoint can take a short while to start serving the index, so treat aValidationExceptionon the first searches as "retry", not "broken". - Write items with an
embeddingattribute as a list of numbers ({"L": [{"N": "0.0123"}, ...]}) with exactly 1,024 values. - Search with
search-vectors(next section).
Backfilling is not proportional to the table size: even a table with a handful of items can take a substantial time, because building the index structure is the slow part. Poll describe-table instead of assuming a small table will be quick. You can create or delete only one index at a time per table, and that limit is shared with GSI creation; a second request fails with LimitExceededException: Subscriber limit exceeded: Only 1 online index can be created or deleted simultaneously per table.
Searching with SearchVectors
Save the query embedding as a plain JSON array of number objects, then search:
[ {"N": "0.0123"}, {"N": "-0.0456"}, {"N": "0.0789"}, ... ]
aws dynamodb search-vectors \
--table-name repair-notes \
--index-name note-embedding \
--search-vector file://query.json \
--top-k 5 \
--search-condition-expression "shop = :s" \
--expression-attribute-values '{":s": {"S": "north"}}' \
--return-consumed-capacity TOTAL
The response lists SearchResults, most similar first, each with the projected attributes and a Score. The embedding itself is left out by default because it is large; ask for it with --projection-expression only if you need it, since returning vectors increases the bytes you pay for. With --return-consumed-capacity, the response includes VectorSearchRequestBytes, the number your bill is based on.
Three request details trip people up:
SearchVectoris a plain list. Do not wrap it in{"L": ...}as you do when storing the vector on an item.- Numbers must be number objects.
{"N": "0.0123"}, not0.0123. - The partition key is required in
--search-condition-expressionwhen the index has one, and only=works.
Lab: what the SDK accepts in a SearchVectors request
We checked these rules against boto3 1.43.118 with botocore's Stubber, which validates a request against the API model without sending it:
| Request | Result |
|---|---|
SearchVector=[{'N': '0.1'}, ...] | Accepted |
SearchVector={'L': [...]} | Rejected in the SDK: Invalid type for parameter SearchVector ... type: <class 'dict'>, valid types: <class 'list'>, <class 'tuple'> |
SearchVector=[0.1, 0.2, 0.3] | Rejected in the SDK: Invalid type for parameter SearchVector[0], value: 0.1, type: <class 'float'>, valid types: <class 'dict'> |
TopK=0 | Rejected in the SDK: valid min value: 1 |
TopK=101 | Passes the SDK, then the service rejects it with "Provided TopK value is out of valid range" (1 to 100) |
So the SDK catches the shape mistakes before they leave your machine, but not the TopK ceiling. Clamp TopK to 100 in your own code.
Python example: Bedrock embeddings + DynamoDB vector search
This script stores repair notes with Titan embeddings and searches them by meaning. It creates the table, adds notes, and searches one shop's notes, retrying the first searches while a new index starts serving:
#!/usr/bin/env python3
"""repair_search.py: semantic search over notes stored in DynamoDB, with Amazon Bedrock Titan embeddings.
python3 repair_search.py create
python3 repair_search.py add ID SHOP "note text"
python3 repair_search.py search SHOP "what to look for"
"""
import json, sys, time
import boto3
REGION, TABLE, INDEX, DIMS = 'us-east-1', 'repair-notes', 'note-embedding', 1024
ddb = boto3.client('dynamodb', region_name=REGION)
bedrock = boto3.client('bedrock-runtime', region_name=REGION)
def embed(text):
body = json.dumps({'inputText': text, 'dimensions': DIMS, 'normalize': True})
resp = bedrock.invoke_model(modelId='amazon.titan-embed-text-v2:0', body=body)
return json.loads(resp['body'].read())['embedding']
def create():
ddb.create_table(
TableName=TABLE, BillingMode='PAY_PER_REQUEST', # vector indexes need on-demand
AttributeDefinitions=[{'AttributeName': 'note_id', 'AttributeType': 'S'},
{'AttributeName': 'shop', 'AttributeType': 'S'}],
KeySchema=[{'AttributeName': 'note_id', 'KeyType': 'HASH'}],
VectorIndexes=[{
'IndexName': INDEX,
'VectorAttribute': {'AttributeName': 'embedding'},
'SearchSchema': [{'AttributeName': 'shop', 'SearchSchemaElementType': 'HASH'}],
'Projection': {'ProjectionType': 'INCLUDE', 'NonKeyAttributes': ['text']},
'Dimensions': DIMS, 'DistanceFunction': 'COSINE'}])
ddb.get_waiter('table_exists').wait(TableName=TABLE)
def add(note_id, shop, text):
vec = [{'N': repr(float(x))} for x in embed(text)]
r = ddb.put_item(TableName=TABLE, ReturnConsumedCapacity='INDEXES',
Item={'note_id': {'S': note_id}, 'shop': {'S': shop}, 'text': {'S': text}, 'embedding': {'L': vec}})
print('stored', note_id, r.get('ConsumedCapacity'))
def search(shop, text, top_k=5, tries=10):
query = [{'N': repr(float(x))} for x in embed(text)] # plain list, not {'L': ...}
for attempt in range(tries): # a new index can reject searches briefly
try:
r = ddb.search_vectors(TableName=TABLE, IndexName=INDEX, SearchVector=query, TopK=top_k,
SearchConditionExpression='shop = :s',
ExpressionAttributeValues={':s': {'S': shop}},
ReturnConsumedCapacity='TOTAL')
break
except ddb.exceptions.ClientError as e:
if e.response['Error']['Code'] != 'ValidationException' or attempt == tries - 1: raise
time.sleep(2 ** attempt)
for hit in r['SearchResults']:
print(f"{hit['Score']:.4f} {hit['Item']['note_id']['S']} {hit['Item']['text']['S'][:70]}")
print('bytes metered:', r.get('ConsumedCapacity', {}).get('VectorSearchRequestBytes'))
if __name__ == '__main__':
cmd = sys.argv[1]
if cmd == 'create': create()
elif cmd == 'add': add(sys.argv[2], sys.argv[3], sys.argv[4])
elif cmd == 'search': search(sys.argv[2], sys.argv[3])
The identity needs bedrock:InvokeModel on the Titan model, the usual DynamoDB table permissions, and dynamodb:SearchVectors on the index (see security). We ran the whole flow through botocore's Stubber, which checks every request (the CreateTable with VectorIndexes, the Bedrock InvokeModel, the PutItem and the SearchVectors) against the current API models: all calls were valid and consumed in order, including one simulated "The table does not have the specified index" that the retry loop rode out. Retrying only on ValidationException keeps real mistakes, such as a wrong index name that never appears, from looping forever; the loop gives up after its last try.
Ethan loaded the 2,000 notes and typed "display blinking after a fall". The top result was a technician's note that said "Galaxy screen flickers after drop, replaced flex cable". "It found it without a single matching word," Jake said. "That's the whole point of the numbers," Ethan said.
Partition keys and inline filters: the search schema
The optional SearchSchema decides how much of the index each search reads:
- HASH (vector index partition key): groups vectors by an attribute such as
shop,tenant_id,categoryorcountry. Each search reads only one partition key value, which lowers latency and cost and spreads throughput. You must pass its value in every search. Choose medium cardinality: a unique ID leaves each partition with one item and nothing to compare, and a true/false value puts most items in one partition. - INLINE_FILTER: up to 18 extra attributes stored next to each vector, such as
languageordoc_type. DynamoDB skips non-matching vectors while it searches, instead of finding matches first and throwing them away. Filters are optional in a search.
Both support only equality. Ranges, <> and IN are not available yet, so "notes from the last 30 days" is not a filter you can express; store a coarse value such as month = "2026-10" instead, or filter the results in your code. Without a partition key, every search reads the whole index, and its cost and latency grow as the index grows.
One write rule deserves its own warning. If an item is missing the partition key attribute (or you REMOVE it), the table write succeeds but the item is silently left out of the vector index: no error, it just never appears in searches. A missing inline filter attribute, by contrast, still gets indexed. A vector with the wrong number of dimensions is rejected outright.
DynamoDB vector search pricing
Vector indexes have two meters of their own, on top of the table's normal charges (US East, Standard table class, October 24, 2026):
| Meter | Price | What it counts |
|---|---|---|
| Vector search | $0.002 per GB (Standard-IA: $0.0025) | VectorSearchRequestBytes: vector data the search examines plus the data it returns |
| Vector writes | $0.52 per GB (Standard-IA: $0.65) | VectorWriteRequestBytes: data written into the index by puts, updates and deletes that change indexed attributes |
| Minimum | 1 KB per request for both meters, then billed per byte; one minimum per write, not per index | |
| Table writes | $0.625 per million write request units | The normal write of the item, embedding included |
| Storage | $0.25 per GB-month (first 25 GB free) | The table's items; the index's storage is separate from the table's |
There is no hourly charge and no cluster to keep running, which is the big difference from a vector database you provision. The price list on October 24 had no separate storage line for vector indexes, so check the first bill to see how the index's storage is shown.
How big is a search? The bytes a search meters depend on the dimensions, how much of the index it has to walk, TopK and the projection, and they grow only slowly as the index grows: doubling the items adds a small, roughly constant amount, because ANN search visits a small part of the index. For scale, take a search that meters VectorSearchRequestBytes: 41714, about 42 KB. A million searches of that size meter about 42 GB, which is about $0.08. Do not estimate from dimensions alone: turn on ReturnConsumedCapacity, run a hundred real queries, and use your own average.
The table write is the bigger cost. The embedding is stored on the item as a DynamoDB number list, and that is far larger than its 4 KB of 32-bit floats. In our DynamoDB Local test, putting one item with a 1,024-number embedding cost 12 write units, whether we wrote the numbers at full Python precision or rounded them to 7 significant digits; rounding to 4 digits brought it to 7. By DynamoDB's documented item-size rule (about one byte per two significant digits, plus one byte per number), rounding should also shrink items in the real service, so measure both in your account. For Jake's 2,000 notes, all of this is pennies; for millions of documents that are re-embedded often, the table writes deserve a line in the budget.
For Jake's shops, with 2,000 notes, 200 new notes a month and about 3,000 searches a month, the DynamoDB side rounds to zero: well under a cent of vector search, a fraction of a cent of vector and table writes, and storage inside the free 25 GB. The embeddings from Bedrock cost more than the database. Our on-demand vs provisioned guide explains the table charges. As with any DynamoDB index, the projection drives the index's write and storage costs, so project only what the results page shows.
Security: why the tenant partition key is not an access control
This is the most important section for anyone building a multi-tenant app or a RAG system with customer data. A common DynamoDB pattern restricts each user to their own items with an IAM condition on dynamodb:LeadingKeys. That does not work for vector search. Fine-grained access control is not supported for SearchVectors: the condition keys dynamodb:LeadingKeys, dynamodb:Attributes and dynamodb:Select have no effect on it.
- Anyone with
dynamodb:SearchVectorson the index can search every partition key value, including every tenant, whatever the HASH key says. - A policy statement that has an FGAC condition and includes
SearchVectorsdenies the search, because the condition keys are absent from the request. GrantSearchVectorsin its own statement, on the index ARN, without those conditions. - For strict tenant isolation, use separate tables or separate indexes with separate IAM grants per tenant. The partition key is a performance feature.
A search-only policy looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SearchRepairNotes",
"Effect": "Allow",
"Action": "dynamodb:SearchVectors",
"Resource": "arn:aws:dynamodb:us-east-1:111122223333:table/repair-notes/index/note-embedding"
}
]
}
Creating and deleting vector indexes needs only dynamodb:CreateTable or dynamodb:UpdateTable, and writing vectors uses the normal PutItem and UpdateItem permissions. The index uses the table's encryption key automatically. Our IAM policy JSON guide explains statements and resource ARNs.
"So both shops can see each other's notes?" Jake asked. "In our case that's fine, they're both yours," Ethan said. "If they were two different customers, I'd give each one its own index."
DynamoDB Local does not support vector search (and does not tell you)
Most teams test DynamoDB code against DynamoDB Local. For vector search, that gives a false picture. We ran DynamoDB Local 3.3.1 in a memory-capped container and created a table with a vector index:
create_table with VectorIndexes: OK
describe keys: [] None
put cc: {'TableName': 'vec-probe', 'CapacityUnits': 1.0, 'Table': {'CapacityUnits': 1.0}}
search_vectors -> ClientError An error occurred (UnknownOperationException) when calling the SearchVectors operation: An unknown operation was requested.
The CreateTable call succeeded, but DescribeTable showed no vector index at all, the put reported no vector write, and the search failed as an unknown operation. Code that creates its tables in DynamoDB Local will pass setup and only fail at the first search. DynamoDB Local's release notes through version 3.3.2 (October 15, 2026) list no vector search support. For now, test vector features against a real table in a development account, keep it small, and delete it afterwards; at these prices a test run costs a fraction of a cent. Our DynamoDB Local guide is still the right tool for everything else.
Endpoints: SearchVectors goes to a different host
Searches do not go to dynamodb.us-east-1.amazonaws.com. They use dedicated vector-search endpoints, and the SDK picks the host for you. We captured the host boto3 1.43.118 chose for a search request (without sending it):
no account id -> https://search-dynamodb.us-east-1.amazonaws.com/
aws_account_id given -> https://111122223333.search-ddb.us-east-1.amazonaws.com/
account id + dual-stack -> https://111122223333.search-ddb.us-east-1.api.aws/
dual-stack only -> https://search-dynamodb.us-east-1.api.aws/
With normal credentials (which usually carry your account ID), searches go to <account-id>.search-ddb.<region>.amazonaws.com, while DescribeTable and PutItem still go to dynamodb.<region>.amazonaws.com. If your servers sit behind an egress firewall or proxy with an allowlist of AWS hostnames, add the search hosts, or writes will work and every search will time out. In private subnets, check that the search endpoint is reachable from where your code runs before you rely on it. If "The table does not have the specified index" persists after the index is ACTIVE, confirm that your network allows the search endpoint hostname.
Calling SearchVectors from AWS Lambda: bundle a newer boto3
If your search code runs in a Lambda function on the Python runtime, check the SDK version first. The Lambda Python 3.13 base image we pulled (built October 13, 2026) ships boto3 and botocore 1.42.97, which predate vector search. Inside that image, the same calls that work on your laptop fail:
AttributeError: 'DynamoDB' object has no attribute 'search_vectors'
ParamValidationError: Parameter validation failed: Unknown parameter in input: "VectorIndexes", must be one of: AttributeDefinitions, TableName, KeySchema, ...
The fix is to package your own boto3 with the function (in the deployment package or a layer, with pip install --target ./package "boto3>=1.43"), so it takes precedence over the runtime's copy. Then log boto3.__version__ once at startup to confirm which one loaded. The same applies to any brand-new AWS API: the runtime's SDK trails the newest release.
Limits and quotas
| Quota | Default | Adjustable |
|---|---|---|
| Vector indexes per table | 5 | Yes (AWS Support) |
| Dimensions per index | 4,096 | No |
| TopK per search | 100 | No |
| Partition keys per index | 1 | No |
| Inline filters per index | 18 | No |
| Search rate per partition key value | 1 GB per second | Yes |
| Index write rate per partition key value | 10 MB per second | Yes |
| Table size for creating an index without allowlisting | 600 GB | Yes |
| Concurrent index creations or deletions per table | 1 | No |
With 768-dimension embeddings and about 1 KB of other data, each item is about 4 KB, so one partition key value supports roughly 250,000 vectors examined per second and 2,500 vector writes per second. Spreading data across more partition key values multiplies those numbers. The 16 MB response cap matters if you project ALL on large items with a high TopK; use a narrower projection and fetch the rest with BatchGetItem.
How vector indexes work with other DynamoDB features
- Consistency: indexing is asynchronous, so a new or changed vector appears in searches after a short delay, even on global tables with multi-Region strong consistency.
- Global tables: the index definition is replicated to every replica Region and items are indexed in each Region. Because ANN is approximate, two Regions can return slightly different orderings for the same query. Our global tables guide covers replication.
- Streams: work as usual. A good pattern is to re-embed changed text from a stream, because DynamoDB never recomputes embeddings for you; an edited note keeps its old vector until you write a new one.
- TTL: expired items are removed from the index too.
- Backups and point-in-time recovery: a restore rebuilds the index from the table, so the restored index backfills before you can search it.
- Export and import: exports to S3 include the vector attributes; on import, define the vector index in the import request.
- DAX: does not support
SearchVectors; send searches straight to DynamoDB, and cache results yourself if you need to.
DynamoDB vector search vs OpenSearch vs a Bedrock Knowledge Base
| Need | Good fit |
|---|---|
| Your data already lives in DynamoDB and you want "find similar" next to it | DynamoDB vector index: no sync pipeline, no cluster, billed per byte |
| Keyword search, typo tolerance, highlighting, hybrid keyword + vector, rich range filters | Amazon OpenSearch, which DynamoDB can feed through a zero-ETL integration |
| A managed RAG pipeline: chunking, embedding and retrieval for documents in S3 | Bedrock Knowledge Bases, with a vector store behind it; see our Knowledge Bases guide |
| SQL joins with vectors | Aurora PostgreSQL with pgvector |
DynamoDB vector search is not full-text search. It will not find an exact part number or a misspelled word the way a keyword index does, and it has no range filters yet. For a support search box, many teams end up with both: vectors for meaning, keywords for exact codes.
A checklist before you ship vector search
- Pick the embedding model, dimensions and distance function, and test relevance on real data before you create the index.
- Choose a partition key that matches how users search (a shop, a tenant, a category), with medium cardinality.
- Project only the attributes the results page shows.
- Make sure every searchable item has the partition key attribute, or it silently drops out of the index.
- Grant
dynamodb:SearchVectorsin its own statement; use separate indexes or tables for strict tenant isolation. - Add the search hostnames to any egress allowlist.
- Retry
ValidationExceptionfor the first searches after an index becomes ACTIVE. - Re-embed items when their text changes, for example from a DynamoDB stream.
- Log
VectorSearchRequestBytesandVectorWriteRequestBytesfor a week, and alarm on the CloudWatch metrics of the same names (dimensionsTableNameandVectorIndexName).
DynamoDB vector search errors and fixes
ValidationException: SearchConditionExpression must be provided when SearchSchema has a HASH key
The index has a partition key and the search did not pass its value. Add it, for example shop = :s, with the matching expression attribute value.
ValidationException: One element in SearchSchema is not defined in attribute definitions
Every partition key and inline filter in the search schema must be declared in AttributeDefinitions with its type.
ValidationException: Invalid comparator used in SearchConditionExpression
Only = is supported. Rewrite ranges and IN as equality on a coarser attribute, or filter in your code.
ValidationException: Provided TopK value is out of valid range
TopK must be from 1 to 100. The SDK catches 0 but not 101, so clamp it in your code.
"Cannot search backfilling vector index" or "The table does not have the specified index"
The index is still building, or it has just become ACTIVE and the search endpoint has not started serving it. Wait for ACTIVE without Backfilling, then retry the search with backoff.
An item never shows up in search results
It is missing the vector index partition key attribute, so it was silently left out of the index. Also check that the vector attribute is a list of numbers with the right number of dimensions.
AccessDeniedException on SearchVectors with a LeadingKeys policy
Fine-grained conditions do not apply to SearchVectors, and a statement that uses them denies the search. Grant SearchVectors in a separate statement on the index ARN.
LimitExceededException: Only 1 online index can be created or deleted simultaneously per table
Another vector index or GSI is being created or deleted on the table. Wait until it finishes, and create indexes one at a time.
UnknownOperationException: An unknown operation was requested
You are calling DynamoDB Local (or a mock) that does not support SearchVectors. Test against a real table.
DynamoDB vector search: frequently asked questions
Does DynamoDB support vector search?
Yes. Since August 5, 2026, DynamoDB has vector indexes and a SearchVectors API for similarity search on embeddings stored in your items, in all commercial Regions, GovCloud (US) and China.
What is DynamoDB vector search?
An approximate nearest neighbor search over a vector index on a DynamoDB table. You pass a query embedding, and DynamoDB returns the most similar items with a similarity score.
How much does DynamoDB vector search cost?
In US East, $0.002 per GB of vector data searched and $0.52 per GB written to the index, with a 1 KB minimum per request, plus the table's normal writes and storage. There is no hourly charge.
Does DynamoDB generate embeddings?
No. Create embeddings with a model such as Amazon Titan Text Embeddings on Bedrock, store them on the item as a list of numbers, and use the same model for query vectors.
How many dimensions can a DynamoDB vector index have?
Up to 4,096. Vectors are stored in the index as 32-bit floats, and the number of dimensions cannot be changed after the index is created.
Can I use vector search on a provisioned DynamoDB table?
No. Vector indexes use on-demand capacity only, and the table must also be on-demand. Switch the table to on-demand first.
Does DynamoDB Local support vector search?
No. In our test, DynamoDB Local 3.3.1 accepted a table with a vector index, left the index out, and rejected SearchVectors as an unknown operation; the release notes through 3.3.2 do not add it.
Can I restrict vector search to one tenant with IAM?
Not per partition key. Fine-grained conditions such as dynamodb:LeadingKeys do not apply to SearchVectors, so anyone allowed to search an index can search all of it. Use separate indexes or tables per tenant.
Can I query a vector index with Query or Scan?
No. Vector indexes are read only through SearchVectors; Query, Scan and PartiQL do not work on them, and DAX does not support SearchVectors.
Is DynamoDB vector search real-time?
Searches are fast, but indexing is asynchronous, so a newly written vector becomes searchable after a short delay rather than at the moment the write succeeds.
DynamoDB vector search vs OpenSearch: which should I use?
DynamoDB if your data is already in DynamoDB and you need similarity search with equality filters and no cluster. OpenSearch if you need keyword search, hybrid search, typo tolerance or range filters.
How do I search DynamoDB for text?
For meaning, use a vector index with embeddings. For exact words and keyword search, DynamoDB has no full-text index; send the data to OpenSearch, for example through the zero-ETL integration.
Is it okay to use full text search on DynamoDB if individual partitions are tiny?
A Query on a small partition plus filtering in your code can work for exact matches, but it is not full-text search. For meaning-based matches, a vector index with a partition key per group is the built-in option now.
Is there a cheaper solution for DynamoDB searching than OpenSearch?
For similarity search, a DynamoDB vector index has no always-on cluster and bills per byte searched, which is very cheap for small and medium workloads. Measure VectorSearchRequestBytes on real queries to compare.
How many vector indexes can a DynamoDB table have?
Five by default. A common use for more than one is comparing two embedding models side by side before switching.
What is the maximum TopK in SearchVectors?
100. Responses are limited to 16 MB and cannot be paginated, so use narrow projections when results are large.
For readers preparing for an AWS certification
We have been covering AWS certifications alongside our fixes, so here is a short extra for readers studying for one. If you only came for the fix, you already have it; feel free to skip this part.
Exams that test this topic: Developer – Associate (DVA-C03 from December 1, 2026) • Solutions Architect – Associate (SAA-C03) • AI Practitioner (AIF-C01).
Here are the exam-style questions this topic tends to raise, with the reasoning you need to answer them:
1. A company stores its product catalog in DynamoDB and wants semantic product search without running another database or a sync pipeline. What should it use?
A DynamoDB vector index on the on-demand table, with embeddings from a model such as Amazon Titan Text Embeddings on Bedrock stored on each item, queried with SearchVectors.
2. A developer creates a vector index and immediately calls SearchVectors, which fails with ValidationException. The index name is correct. What should the developer do?
Wait until DescribeTable shows the index ACTIVE without Backfilling, then retry searches with backoff, because the search endpoint can lag briefly after the index becomes ACTIVE.
3. A multi-tenant application restricts each tenant with dynamodb:LeadingKeys and wants to add vector search over tenant documents with strict isolation. What is the correct design?
Fine-grained access control does not apply to SearchVectors, so use a separate vector index or table per tenant with separate IAM grants; the vector index partition key is not a security boundary.
4. Items written to a table whose vector index has a partition key never appear in search results, though the writes succeed. What is the likely cause?
The items lack the vector index partition key attribute, so DynamoDB silently leaves them out of the vector index.
5. What is a vector embedding, and why must stored vectors and query vectors come from the same model?
A list of numbers a model produces so that similar content lands close together; vectors from different models (or dimensions) are not comparable, so mixed models give meaningless results.
6. Which distance function is the usual default for semantic search over text embeddings, and how are its scores read?
COSINE, which compares direction and ignores magnitude; scores run from 0 (most similar) to 2 (opposite), so lower is better.
Exam codes and dates change often. Our AWS certification changes page keeps track of what is current.
Two weeks in, the technicians use the search box more than the shared spreadsheet it replaced. Ethan's monthly DynamoDB charge for it was less than the coffee he bought the day he set it up. "And the other shop can't see ours?" Jake asked. "They can, because they're both yours," Ethan said. "When we sell the software to a third shop, it gets its own index." If your results differ from what this page describes, please tell us. Guides like this stay right because readers write in.
📌 If you keep one line from this page
DynamoDB vector search is cheap and easy on an on-demand table, but its partition key is not an access control and DynamoDB Local silently ignores it, so isolate tenants with separate indexes and test against a real table.
GA August 5, 2026 · 4,096 dimensions · TopK 100 · $0.002/GB searched · $0.52/GB written · on-demand only · October 24, 2026.
Revision note. Written October 24, 2026, from SDK, endpoint and DynamoDB Local tests and that day's US East prices. "Birds of a feather flock together," the old saying goes, and that is all a vector index does, very quickly.