DEV Community

Cover image for Amazon DynamoDB Vector Search. No Separate Vector Store
Elizabeth Fuentes L for AWS

Posted on Originally published at builder.aws.com

Amazon DynamoDB Vector Search. No Separate Vector Store

📦 Clone and ⭐ stop-ai-agents-losing-memory-sample-for-aws

Part 1 of this post showed how keyword search misses semantic questions and measured two vector backends: FAISS and Amazon S3 Vectors (managed), on the same traveler memories. Both found the answer. The difference was deployment: local vs cloud-managed.

This part adds a third vector backend: Amazon DynamoDB Vector Search, generally available since 2025. The question and the memories are identical. Only the backend changes.

stored:   dietary_notes: "Vegetarian; severe shellfish allergy  strictly no
          crustaceans or mollusks."

asked:    "What should I avoid eating when I go out for dinner on this trip?"

DynamoDB Vector Search: top hit (score 0.231)  answer found: True
Enter fullscreen mode Exit fullscreen mode

What is Amazon DynamoDB Vector Search?

It is a vector index added to an existing DynamoDB table. Not a separate service. You define a VectorIndexes block when you create (or update) the table, and DynamoDB stores the embeddings as a List attribute on each item. Queries use the SearchVectors API.

The key difference from S3 Vectors: the vectors live in the same table as your operational data. If your agent already reads user preferences or travel records from DynamoDB, you can add a vector index to that same table and query by meaning without provisioning another service.

Amazon S3 Vectors Amazon DynamoDB Vector Search
Where vectors live Dedicated vector bucket Inside a DynamoDB table
Operational data collocated No Yes
Query latency ~100–200 ms Single-digit ms
Billing model Per-query + storage On-demand (PAY_PER_REQUEST)
Accuracy ✅ same (same embeddings) ✅ same (same embeddings)
Survives restart Yes Yes
Infrastructure to manage None None
Best for Dedicated vector memory, no operational data to manage Agents that already use DynamoDB, or want one service for data + embeddings

Both are valid choices. S3 Vectors is purpose-built for dedicated vector workloads and the right fit when you want memory completely separate from your operational data. DynamoDB Vector Search is the right fit when your agent data is already in DynamoDB and you want one service for both.

(This demo uses Strands Agents. The pattern carries over to any agent framework.)

DynamoDB Vector Search stores embeddings inside the existing table alongside operational data, unlike S3 Vectors which uses a separate dedicated bucket


How does the embedding comparison look?

Same question, same Titan V2 embeddings, four backends side by side:

Store Finds answer cos_sim Query latency
Key-value (keyword scan) No
FAISS Yes 0.231 <0.1 ms
Amazon S3 Vectors Yes 0.231 ~195 ms
Amazon DynamoDB Vector Search Yes 0.231 single-digit ms

All three vector backends return the same top hit with the same score, because they use the same Amazon Titan Text Embeddings V2 model. The embedding call (~510 ms) still dominates end-to-end latency for all of them. What changes is the query after the embedding.


How do you add a vector index to a DynamoDB table?

DynamoDB Vector Search requires on-demand billing (PAY_PER_REQUEST). The vector index is declared when creating the table:

client.create_table(
    TableName="agent-memory-demo-ddb",
    BillingMode="PAY_PER_REQUEST",           # required for vector indexes
    KeySchema=[{"AttributeName": "memory_key", "KeyType": "HASH"}],
    AttributeDefinitions=[{"AttributeName": "memory_key", "AttributeType": "S"}],
    VectorIndexes=[{
        "IndexName": "memory-vector-index",
        "VectorAttribute": {"AttributeName": "embedding"},
        "Dimensions": 1024,
        "DistanceFunction": "COSINE",
        "Projection": {"ProjectionType": "ALL"},
    }],
)
Enter fullscreen mode Exit fullscreen mode

The demo self-provisions the table and index if missing: no console steps, no CDK required.


How do you write and query vectors?

Embeddings are stored as a DynamoDB List attribute alongside the rest of the item:

client.put_item(
    TableName="agent-memory-demo-ddb",
    Item={
        "memory_key":  {"S": "dietary_notes"},
        "text":        {"S": "Vegetarian; severe shellfish allergy..."},
        "embedding":   {"L": [{"N": str(float(f))} for f in vector]},  # 1024 floats
    },
)
Enter fullscreen mode Exit fullscreen mode

Querying uses the SearchVectors API with the same AttributeValue format:

resp = client.search_vectors(
    TableName="agent-memory-demo-ddb",
    IndexName="memory-vector-index",
    SearchVector=[{"N": str(float(f))} for f in question_vector],
    TopK=3,
)
Enter fullscreen mode Exit fullscreen mode

Score note: SearchVectors returns a cosine distance (lower = more similar). The demo converts it to cosine similarity (1.0 − score) so the output is directly comparable to FAISS and S3 Vectors.


Does the index survive a restart?

Yes. It's DynamoDB. A fresh client instantiated after the demo runs still sees every item:

fresh = DynamoDBVectorStore()
fresh.count() == 10   # True — all 10 memories are there
Enter fullscreen mode Exit fullscreen mode

This is the same restart test run in Part 1 for S3 Vectors. Both pass.


How do you run Test 4?

Test 4 runs as part of the existing test_vector_memory.py in the companion repo:

git clone https://github.com/elizabethfuentes12/stop-ai-agents-losing-memory-sample-for-aws
cd stop-ai-agents-losing-memory-sample-for-aws/02-vector-memory-demo
uv venv && uv pip install -r requirements.txt
uv run python test_vector_memory.py
Enter fullscreen mode Exit fullscreen mode

Needs AWS credentials (aws configure) for Titan embeddings (Bedrock), S3 Vectors, and DynamoDB. The demo creates the DynamoDB table and vector index automatically if they don't exist. Requires boto3>=1.43.72 (SearchVectors was added in that release).


When do you pick DynamoDB over S3 Vectors?

You have Pick
No existing DynamoDB table; memory is the only use case S3 Vectors — purpose-built for dedicated vector workloads
An existing DynamoDB table with user data DynamoDB Vector Search — add the index to the same table; one service, one billing model
Need sub-100 ms query latency after the embedding call DynamoDB Vector Search — single-digit ms vs ~200 ms
High QPS, hybrid search, or advanced filtering Dedicated vector database (OpenSearch, Qdrant, etc.)

FAQ

Can I add a vector index to an existing DynamoDB table?
Yes. Use update_table with VectorIndexUpdates to add the index to a table that already has data. Existing items without the embedding attribute won't appear in vector queries until you backfill their embeddings and update the items.

Does DynamoDB Vector Search work in all regions?
Check regional availability; the feature is GA but not in every region on launch day.

What's the cost compared to S3 Vectors?
DynamoDB Vector Search uses on-demand billing: you pay for read/write capacity units and storage on the table. S3 Vectors charges per query and per stored vector. For agent memory workloads (infrequent queries, small number of vectors per user) both are low cost; the deciding factor is architecture, not price.

Why does SearchVectors return a distance and not a similarity?
SearchVectors returns cosine distance (1 − cosine_similarity), where 0 means identical and 1 means opposite. The demo converts with 1.0 − score to get cosine similarity for easy comparison with FAISS (which returns inner product of normalized vectors, equivalent to cosine similarity) and S3 Vectors (which also returns 1 − distance).


Resources


Which surprised you more: the single-digit millisecond DynamoDB latency, or the fact that the cosine similarity score is identical across all four backends? Share in the comments.


Gracias!

🇻🇪 Dev.to Linkedin GitHub Twitter Instagram Youtube


Top comments (0)