DynamoDB Vector Search Setup: 13 Steps, 100 Min [2026]

On August 5, 2026, AWS flipped a switch that a lot of backend teams had been waiting on for over a year: DynamoDB can now run native vector search. No side-car cluster, no second bill, no data pipeline shipping embeddings out to a separate store. If you have been bolting Pinecone or OpenSearch onto a DynamoDB-backed app just to support semantic search or retrieval-augmented generation (RAG), this changes the calculus. This tutorial walks through building a working AWS vector database on top of DynamoDB from a cold AWS account to a queryable RAG pipeline, including the exact CLI commands, boto3 code, pricing math, and the mistakes that trip up most first attempts.

We will build a real product-search index with 1,024-dimension embeddings, wire it into Amazon Bedrock for generation, and benchmark it against the alternatives (Amazon OpenSearch Service, Amazon S3 Vectors, Aurora pgvector, and Pinecone) so you know when DynamoDB is the right call and when it is not. Expect roughly 100 minutes end to end if you already have an AWS account with billing enabled.

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

What Is DynamoDB Vector Search, and Why It Matters for an AWS Vector Database Stack

Vector search is how modern apps do semantic lookup: instead of matching exact keywords, you convert text, images, or audio into a numeric embedding and find the nearest neighbors in that vector space. Until this summer, running that workload on AWS meant standing up Amazon OpenSearch Service, which since its 3.1 release in September 2025 has used Lucene 10-optimized vector indexing along with a vector quantization scheme that cut memory usage for large indexes, paying for an S3 Vectors bucket layer, or self-hosting Pinecone, Weaviate, or Qdrant next to your primary database. Each option added a second system to operate, a second bill, and a data-sync job to keep embeddings fresh.

DynamoDB vector search removes that second system for a specific and common case: apps that already store their operational data in DynamoDB and need real-time semantic lookups on the same items. AWS built a new index type, called a vector index, that sits alongside your existing global secondary indexes (GSIs) and local secondary indexes (LSIs). You attach the vector index to an attribute holding an embedding, and DynamoDB runs approximate nearest neighbor (ANN) search against it through a new API called SearchVectors. AWS reports single-digit millisecond latency at 99%+ recall, and positions the feature as scaling to trillions of vectors because it inherits DynamoDB’s existing horizontal partitioning.

The feature is available in every commercial AWS Region plus AWS GovCloud (US), which matters if your app serves regulated workloads. It supports three distance functions, cosine similarity, Euclidean (L2) distance, and dot product, and vectors up to 4,096 dimensions, which comfortably covers popular embedding models from Amazon Bedrock (Titan Text Embeddings V2 at 1,024 dimensions), Cohere Embed, and OpenAI’s text-embedding models.

One caveat worth stating up front: DynamoDB vector search is not currently a supported backend for Amazon Bedrock Knowledge Bases. AWS has broadened Knowledge Bases’ own vector store lineup since then, adding Amazon OpenSearch managed clusters as a supported option in March 2025 and expanding that general availability to every existing Bedrock region that same month, but DynamoDB itself never made the list. If you want managed RAG ingestion where Bedrock handles chunking and embedding for you, you still need OpenSearch (Serverless or managed cluster) or Aurora as the knowledge base store. DynamoDB vector search is a build-it-yourself retrieval layer, which gives you more control over schema and cost, at the price of writing your own embed-and-write loop. We will build exactly that loop in this tutorial.

Prerequisites: Versions, Accounts, and Tools You Need

Vector search requires an updated DynamoDB service model, so check your tooling before you start rather than debugging a mystery error thirty minutes in. Here is the exact list:

  • An AWS account with billing enabled and permissions to create IAM roles, DynamoDB tables, and invoke Amazon Bedrock models.
  • AWS CLI version that includes the DynamoDB service model update released on August 4, 2026, or later. Run aws --version and update if your CLI predates that release.
  • Python 3.10 or newer, with boto3 upgraded past the August 4, 2026 service model (pip install boto3 --upgrade).
  • Access enabled to at least one Amazon Bedrock embedding model in your Region, typically Amazon Titan Text Embeddings V2. Enable it under Bedrock model access before you start Step 5.
  • A terminal with jq installed (optional, but it makes reading CLI JSON output far less painful).
  • Roughly 100 minutes and an AWS budget of under $2 for the full tutorial, assuming you clean up resources afterward as shown in Step 12.

Run this quick version check before moving on. If either command errors out or reports an old version, upgrade first.

aws --version
# aws-cli/2.31.x Python/3.13.x ...  (must be dated on or after 2026-08-04)

python3 -c "import boto3; print(boto3.__version__)"
# Must be a build published after the 2026-08-04 DynamoDB service model update

pip install --upgrade awscli boto3

Step 1: Set Up Your AWS Account and an IAM Role Scoped to DynamoDB Vector Search

Skip the temptation to test this with your root account or an IAM user with AdministratorAccess. Create a scoped IAM policy instead, both for security and because it forces you to see exactly which permissions the SearchVectors API needs. Save the following as vector-search-policy.json.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DynamoDBVectorSearch",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateTable",
        "dynamodb:DescribeTable",
        "dynamodb:PutItem",
        "dynamodb:BatchWriteItem",
        "dynamodb:GetItem",
        "dynamodb:Query",
        "dynamodb:SearchVectors",
        "dynamodb:DeleteTable"
      ],
      "Resource": "arn:aws:dynamodb:*:*:table/Products*"
    },
    {
      "Sid": "BedrockEmbeddings",
      "Effect": "Allow",
      "Action": ["bedrock:InvokeModel"],
      "Resource": "arn:aws:bedrock:*::foundation-model/amazon.titan-embed-text-v2:0"
    }
  ]
}

Create the IAM user or role, attach this policy, and configure a named CLI profile so the rest of this tutorial does not touch any other AWS resources in your account by accident.

aws iam create-policy --policy-name VectorSearchTutorialPolicy \
  --policy-document file://vector-search-policy.json

aws configure --profile vector-tutorial
# Enter your access key, secret key, and preferred Region (e.g. us-east-1)

Step 2: Confirm the DynamoDB Vector Search API Is Live in Your Region

Vector search shipped to all commercial Regions and GovCloud (US) at general availability, but it costs nothing to verify before you build against it. Run a describe call against the DynamoDB service to confirm your CLI recognizes the vector-index parameters.

aws dynamodb create-table help --profile vector-tutorial | grep -i vector

If that grep returns nothing, your CLI is still on the pre-vector service model and none of the commands in this tutorial will parse. Re-run the upgrade command from the prerequisites section before continuing.

Step 3: Choose an Embedding Model and Plan Your Table Schema

Every vector search project lives or dies on this decision, and it is the one step people skip. Pick one embedding model and commit to it for the life of the index. Mixing embeddings from different models, or even different versions of the same model, inside one vector index produces garbage similarity scores because the vector spaces are not comparable.

For this tutorial we use Amazon Titan Text Embeddings V2 through Bedrock, which outputs 1,024-dimension vectors and normalizes cleanly for cosine similarity. That is also the model AWS uses in its own official DynamoDB vector search tutorial, so if you get stuck, official docs and this article will match step for step.

Our schema is a product catalog, a common real-world case for semantic search: users type “warm waterproof jacket for hiking” and expect relevant results even if no product title contains those exact words.

AttributeTypePurpose
PKStringPartition key, e.g. PRODUCT#123
SKStringSort key, e.g. PRODUCT
nameStringProduct title, shown in results
categoryStringUsed for metadata filtering in Step 8
descriptionStringSource text that gets embedded
embeddingList of Numbers1,024-dim Titan Text Embeddings V2 vector

Step 4: Create a DynamoDB Table With a Vector Index

Now create the table itself. The vector index is defined at table-creation time as a separate index block, distinct from your GSIs. Set the dimension to match your embedding model exactly (1,024 for Titan Text Embeddings V2) and choose cosine as the distance function, since Titan embeddings are designed for cosine comparison.

aws dynamodb create-table \
  --table-name Products \
  --attribute-definitions \
    AttributeName=PK,AttributeType=S \
    AttributeName=SK,AttributeType=S \
  --key-schema \
    AttributeName=PK,KeyType=HASH \
    AttributeName=SK,KeyType=RANGE \
  --billing-mode PAY_PER_REQUEST \
  --vector-indexes '[
    {
      "IndexName": "embedding-index",
      "AttributeName": "embedding",
      "Dimension": 1024,
      "DistanceType": "COSINE",
      "CapacityMode": "ON_DEMAND"
    }
  ]' \
  --profile vector-tutorial

Confirm the table and index are active before moving on, since writes against a table whose vector index is still initializing will succeed but will not appear in search results yet.

aws dynamodb describe-table --table-name Products --profile vector-tutorial \
  | grep -A5 VectorIndex

Step 5: Generate Embeddings With Amazon Bedrock Titan

With the table ready, write a small Python function that calls Bedrock’s Titan Text Embeddings V2 model and returns a 1,024-float vector for any string. This is the function every write and every query will call, so keep the model ID as a constant rather than hardcoding it in multiple places.

import boto3
import json

bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
EMBEDDING_MODEL_ID = "amazon.titan-embed-text-v2:0"

def get_embedding(text: str) -> list[float]:
    response = bedrock.invoke_model(
        modelId=EMBEDDING_MODEL_ID,
        body=json.dumps({"inputText": text, "dimensions": 1024, "normalize": True}),
    )
    result = json.loads(response["body"].read())
    return result["embedding"]

# Quick sanity check
vec = get_embedding("waterproof hiking jacket with insulated lining")
print(len(vec), vec[:5])
# 1024 [0.0123, -0.0341, 0.0089, ...]

Note the normalize: True flag. Titan Text Embeddings V2 supports normalized output, which keeps vector magnitudes consistent and improves cosine similarity accuracy. If you skip normalization, you can still search, but ranking quality drops on catalogs with wide variance in description length.

Step 6: Load Items Into DynamoDB With Their Vectors Attached

Now write items to the table. Each item carries its normal attributes plus the embedding, generated on the fly from the product description. For a real catalog you would batch this with BatchWriteItem and a queue, but a simple loop is fine for the 50-item sample we are loading here, which mirrors the scale AWS uses in its own official tutorial.

import boto3

dynamodb = boto3.client("dynamodb", region_name="us-east-1")
TABLE_NAME = "Products"

def put_product(product_id: str, name: str, category: str, description: str):
    embedding = get_embedding(description)
    dynamodb.put_item(
        TableName=TABLE_NAME,
        Item={
            "PK": {"S": f"PRODUCT#{product_id}"},
            "SK": {"S": "PRODUCT"},
            "name": {"S": name},
            "category": {"S": category},
            "description": {"S": description},
            "embedding": {"L": [{"N": str(x)} for x in embedding]},
        },
    )

put_product(
    "101",
    "Trailblazer Insulated Jacket",
    "Outerwear",
    "Warm waterproof hiking jacket with insulated lining and sealed seams",
)
print("Loaded product 101")

Loop this call across your full catalog before moving to Step 7. Watch item size as you go: the embedding attribute alone for a 1,024-dimension vector adds roughly 15 to 20 KB per item once encoded as a DynamoDB number list, which matters if your existing items are already close to the 400 KB DynamoDB item limit.

Step 7: Run Your First SearchVectors Query

This is the payoff step. Embed a natural-language search query the same way you embedded the product descriptions, then call SearchVectors with that vector and a TopK value. DynamoDB returns the closest matches ranked by similarity score, up to a maximum of 100 results per call.

def search_products(query_text: str, top_k: int = 5):
    query_vector = get_embedding(query_text)
    response = dynamodb.search_vectors(
        TableName=TABLE_NAME,
        IndexName="embedding-index",
        QueryVector={"L": [{"N": str(x)} for x in query_vector]},
        TopK=top_k,
    )
    return response["Items"]

results = search_products("something warm for cold weather hikes")
for item in results:
    print(item["name"]["S"], "-", item["SimilarityScore"]["N"])

Expected output on our sample catalog looks like this, with the Trailblazer jacket ranking first even though the query never used the word “jacket”:

Trailblazer Insulated Jacket - 0.8912
Summit Fleece Pullover - 0.8433
Alpine Wool Beanie - 0.8021
Ridge Runner Thermal Gloves - 0.7788
Basecamp Down Vest - 0.7654

You can also run the equivalent query straight from the CLI, which is useful for quick debugging without spinning up a Python shell.

aws dynamodb search-vectors \
  --table-name Products \
  --index-name embedding-index \
  --query-vector file://query_vector.json \
  --top-k 5 \
  --profile vector-tutorial

Step 8: Add Metadata Filters to Narrow Results

Pure similarity ranking is not always enough. Most product searches also need a category, price range, or availability filter layered on top. SearchVectors accepts a FilterExpression using the same syntax as DynamoDB Query, applied against non-vector attributes on the same item.

def search_products_filtered(query_text: str, category: str, top_k: int = 5):
    query_vector = get_embedding(query_text)
    response = dynamodb.search_vectors(
        TableName=TABLE_NAME,
        IndexName="embedding-index",
        QueryVector={"L": [{"N": str(x)} for x in query_vector]},
        TopK=top_k,
        FilterExpression="category = :c",
        ExpressionAttributeValues={":c": {"S": category}},
    )
    return response["Items"]

results = search_products_filtered("warm winter layer", "Outerwear")

Keep the filter to simple equality and attribute-exists checks. SearchVectors does not currently support range filters or hybrid keyword-plus-vector scoring the way OpenSearch does, so if you need “price between $50 and $150 AND semantically similar,” you will filter client-side after retrieving a larger TopK, or route that query type to OpenSearch instead — a stronger option now that AWS added GPU-accelerated vector indexes to OpenSearch in December 2025, letting it build billion-scale vector databases in under an hour.

Step 9: Build a Minimal RAG Pipeline on Top of DynamoDB Vector Search

Since DynamoDB is not a native Bedrock Knowledge Bases target, you own the retrieval-and-generate loop yourself. That is more code than clicking “create knowledge base,” but it also means you control exactly what gets retrieved and how it gets formatted into the prompt. Here is the full loop: embed the question, search DynamoDB, build context, call a Bedrock text model to generate an answer.

def answer_question(question: str) -> str:
    matches = search_products(question, top_k=3)
    context = "\n".join(
        f"- {m['name']['S']}: {m['description']['S']}" for m in matches
    )
    prompt = f"""Using only the product context below, answer the customer question.

Context:
{context}

Question: {question}
Answer:"""

    response = bedrock.invoke_model(
        modelId="anthropic.claude-sonnet-4-6",
        body=json.dumps({
            "anthropic_version": "bedrock-2023-05-31",
            "max_tokens": 300,
            "messages": [{"role": "user", "content": prompt}],
        }),
    )
    result = json.loads(response["body"].read())
    return result["content"][0]["text"]

print(answer_question("What should I wear hiking in cold, wet weather?"))

This pattern, embed, search DynamoDB, stuff context, generate, is the entire shape of a RAG app. If you have already built agents against Amazon Bedrock, this retrieval step slots in as a tool call rather than a separate service, which is the main appeal of keeping vectors inside DynamoDB instead of a dedicated vector database.

Step 10: Monitor Capacity, Cost, and Index Health

DynamoDB vector search adds dedicated pricing line items on top of standard DynamoDB charges. Alongside the usual on-demand or provisioned read/write capacity for the table and storage for the items (including the embedding attribute), you pay for vector index storage at $0.25 per GB-month, ingestion at $0.52 per GB written into a vector index, and $0.002 per GB processed and returned by SearchVectors queries (us-east-1 rates, billed per byte with a 1 KB minimum; full pricing at aws.amazon.com/dynamodb/pricing).

Watch three numbers in CloudWatch as your catalog grows: consumed read capacity on the vector index, item size distribution (to catch approaching the 400 KB limit), and write throttling events during bulk loads. On-demand capacity mode, which we used in Step 4, is the safer default while you are still learning your traffic pattern, and you can switch to provisioned capacity later once usage stabilizes.

aws cloudwatch get-metric-statistics \
  --namespace AWS/DynamoDB \
  --metric-name ConsumedReadCapacityUnits \
  --dimensions Name=TableName,Value=Products \
  --start-time 2026-08-22T00:00:00Z \
  --end-time 2026-08-22T23:59:59Z \
  --period 3600 \
  --statistics Sum \
  --profile vector-tutorial

Step 11: Benchmark Latency and Test at Scale

Before shipping this to production, measure latency against your own catalog size rather than trusting the headline single-digit-millisecond figure blindly. AWS’s own performance claim, single-digit milliseconds at 99%+ recall, holds up in early adopter write-ups on catalogs in the tens to hundreds of thousands of items, with latency staying stable as the underlying table scales because it inherits DynamoDB’s partitioning rather than running on a fixed-size cluster.

import time

def benchmark_search(query_text: str, runs: int = 20):
    latencies = []
    for _ in range(runs):
        start = time.perf_counter()
        search_products(query_text, top_k=10)
        latencies.append((time.perf_counter() - start) * 1000)
    latencies.sort()
    print(f"p50: {latencies[len(latencies)//2]:.1f}ms")
    print(f"p95: {latencies[int(len(latencies)*0.95)]:.1f}ms")

benchmark_search("comfortable running shoes for trail terrain")

Run this at your real catalog size, not the 50-item demo, before you commit to DynamoDB vector search over a dedicated engine. AWS has not published exhaustive queries-per-second benchmarks in its documentation, so your own numbers are the ones that matter for capacity planning.

Step 12: Clean Up Every Resource You Created

On-demand DynamoDB tables do not cost much sitting idle, but there is no reason to leave a test table and its vector index running past this tutorial. Delete the table, which removes the vector index along with it, and revoke the IAM policy if you created a dedicated user for this exercise.

aws dynamodb delete-table --table-name Products --profile vector-tutorial
aws iam delete-policy --policy-arn arn:aws:iam::<ACCOUNT_ID>:policy/VectorSearchTutorialPolicy

AWS Vector Database Options Compared: DynamoDB vs OpenSearch vs S3 Vectors vs Aurora pgvector vs Pinecone

DynamoDB vector search is not a universal replacement for every other AWS vector database option, and it should not be pitched as one. It solves a specific problem well: apps that already run on DynamoDB and need low-latency semantic lookup on the same items, without standing up a second cluster. AWS’s own Prescriptive Guidance, last updated in August 2026, now catalogs more than five vector store options for RAG workloads on the platform, including MemoryDB, whose vector search supports up to 32,768 dimensions and as many as 10 indexes per cluster as of March 2026, and Neptune Analytics, which as of August 2026 allows one vector index per graph at dimensions ranging from 1 to 65,535. Here is how DynamoDB stacks up against the alternatives most teams actually weigh it against on the metrics that drive an architecture decision.

ServiceStorage modelQuery typeTypical latencyPricing basis
DynamoDB vector searchKey-value, vector index on item attributeANN via SearchVectorsSingle-digit ms at 99%+ recallDynamoDB RCU/WCU + storage, plus dedicated vector charges ($0.25/GB-mo index storage, $0.52/GB ingest, $0.002/GB searched)
Amazon OpenSearch ServiceManaged Lucene-based clusterk-NN, hybrid keyword + vectorLow ms, depends on shard countInstance hours + EBS + data transfer
Amazon S3 VectorsObject storage + managed vector indexBatch or near-real-time ANNHigher than DynamoDB, built for scale over speedS3 storage + index compute
Aurora PostgreSQL + pgvectorRelational, pgvector extensionExact or ANN via extensionLow-to-mid ms depending on index configAurora instance hours + storage + I/O
Pinecone (managed SaaS)Dedicated vector databaseANN, purpose-built indexesLow ms, tuned for high QPSPod size, RAM/CPU, index size tiers

The practical rule of thumb: reach for DynamoDB vector search when your primary data already lives in DynamoDB and you need real-time RAG or semantic API responses without a second store. Reach for OpenSearch when you need hybrid keyword-plus-vector search or complex range filtering DynamoDB’s SearchVectors does not yet support — the OpenSearch project’s own 3.8 release in August 2026 pushed vector ingestion up to 4.2x faster and radial-search throughput up to 2.1x higher, so that performance gap keeps narrowing. Reach for S3 Vectors when you are indexing a huge offline corpus, like a document lake, where sub-5ms latency is not the constraint. And reach for pgvector on Aurora when your data model is genuinely relational and you want joins alongside vector lookups — Aurora has kept that path current, adding pgvector 0.8.0 support on PostgreSQL 16.8 in April 2025, carrying it alongside PostGIS 3.5.1 forward into Aurora PostgreSQL major version 17 that May, and in August 2026 publishing binary quantization guidance for Aurora PostgreSQL covering both 16.8+ and 17.x to shrink vector index storage further.

DynamoDB Vector Search Specs and Limits at a Glance

SpecValue
GA dateAugust 5, 2026
Region availabilityAll commercial AWS Regions + AWS GovCloud (US)
Max vector dimensions4,096
Distance functionsCosine, Euclidean (L2), dot product
Max results per SearchVectors call100
Bedrock Knowledge Bases supportNot a native target; DIY embed-and-write loop required
DynamoDB item size limit400 KB (unchanged, embeddings count against it)
Minimum CLI/SDK versionService model dated 2026-08-04 or later

Choosing an Embedding Model: Titan vs Cohere vs OpenAI on DynamoDB

DynamoDB vector search does not care which embedding model produced your vectors, it only cares about dimension count and distance function consistency. That means the model choice is entirely yours, and it is worth making deliberately rather than defaulting to whatever example you copy from a blog post. Three options dominate real deployments on AWS right now: Amazon Titan Text Embeddings V2 through Bedrock, which as of August 2026 documentation supports 256-, 512-, or 1,024-dimension output plus a binary vector mode for leaner storage; the older Titan Embeddings G1 – Text model, still listed among Bedrock Knowledge Bases’ supported embeddings at a fixed 1,536 dimensions; Cohere Embed also through Bedrock; and OpenAI’s text-embedding models called directly via API.

ModelDimensionsAccess pathBest fit
Titan Text Embeddings V21,024 (configurable down to 256 or 512)Amazon Bedrock, same account as DynamoDBTeams that want everything, embeddings and generation, inside one AWS bill and one IAM boundary
Cohere Embed (v3/v4 family)1,024Amazon BedrockMultilingual catalogs, since Cohere’s embedding models cover a wider language set than Titan
OpenAI text-embedding modelsUp to 3,072Direct API call outside AWSTeams already standardized on OpenAI for generation and want embedding parity across their stack

Staying inside Bedrock keeps latency lower, since the embedding call and the DynamoDB write happen inside the same Region without crossing the public internet, and it keeps your IAM story simpler because you are not managing a second vendor’s API key alongside AWS credentials. The tradeoff is model choice. If your product needs a specific OpenAI or open-source embedding model for compatibility with an existing pipeline, calling out to that provider still works fine with DynamoDB vector search, since the index only stores the resulting float array. Just remember that every writer and every query path across your entire application has to call the exact same model, at the exact same dimension setting, or your similarity scores stop meaning anything.

A Worked Cost Example: What a 100,000-Item Vector Index Actually Costs

Pricing pages are abstract until you run real numbers, so here is a rough worked example for a mid-sized product catalog, 100,000 items, each carrying a 1,024-dimension Titan embedding alongside typical product attributes (name, description, category, price). This is not an official AWS quote, it is a back-of-envelope estimate using DynamoDB’s published on-demand pricing structure, useful for sizing conversations with your finance team before you commit to an architecture.

  • Storage: each item runs roughly 5 to 6 KB once you include the embedding attribute (about 4 KB for the 1,024-float vector plus 1 to 2 KB of product data). At 100,000 items, that is roughly 500 to 600 MB of table storage, a small fraction of a cent per GB-month under standard DynamoDB storage pricing.
  • Write capacity: the initial load of 100,000 items, each consuming a handful of write capacity units for the larger item size, is a one-time cost measured in a few dollars under on-demand pricing, not a recurring line item.
  • Read capacity for search: each SearchVectors call consumes read capacity proportional to the ANN search work performed. A catalog of this size running a modest few thousand searches per day sits comfortably within typical on-demand read pricing, generally landing in the tens of dollars per month range for the vector search read traffic specifically, separate from whatever your existing DynamoDB workload already costs.
  • Vector index charges: on top of standard table capacity, DynamoDB bills vector index storage at $0.25 per GB-month, ingestion at $0.52 per GB written into the index, and $0.002 per GB processed and returned by SearchVectors (us-east-1 rates, billed per byte with a 1 KB minimum). For a catalog this size the ingest is a small one-time charge and index storage runs a few cents per month, while search cost scales with query volume.
  • Bedrock embedding calls: generating embeddings for 100,000 product descriptions, plus ongoing embeddings for user queries at search time, adds a Bedrock invocation cost on top of DynamoDB. Query-time embedding cost scales with search volume, not catalog size, so it stays flat as your product count grows.

The comparison that matters is not “DynamoDB vector search is free,” it is not, but rather what you avoid paying: no OpenSearch cluster sized for 24/7 uptime, no separate Pinecone pod tier, no data-sync Lambda function keeping two stores consistent. For a catalog of this size, folding vector search into an existing DynamoDB table you are already paying for is very likely cheaper than standing up and operating a dedicated vector database cluster, though you should always validate against your own traffic pattern using the AWS Pricing Calculator before committing budget.

Common Pitfalls When Building an AWS Vector Database on DynamoDB

Every one of these showed up in early adopter write-ups and the DynamoDB docs’ own troubleshooting notes. Read this section before your first production deploy, not after.

  • Dimension mismatch between stored and query vectors. If your index is defined at 1,024 dimensions and a query vector comes in at 1,536 because someone swapped embedding models, the call fails validation outright. Pin your embedding model as a constant in code, not a config value someone can silently change.
  • Mixing embedding model versions inside one index. Titan Text Embeddings V1 and V2 vectors are not comparable. If you upgrade models, you need to re-embed your entire catalog and, in most cases, rebuild the index rather than mixing old and new vectors.
  • Item size creeping toward the 400 KB ceiling. A 1,024-dimension embedding adds meaningful bytes to every item. If your existing items already carry large text blobs or nested attributes, budget for the embedding before you hit a silent write failure in production.
  • Expecting hybrid keyword-plus-vector search. DynamoDB SearchVectors does pure ANN with basic equality filters. If your product needs BM25-style keyword relevance blended with semantic similarity, you need OpenSearch, not DynamoDB, for that specific query pattern.
  • Running an outdated CLI or SDK. Vector search requires the service model update from August 4, 2026. Older CLI and boto3 installs will not even recognize the vector-indexes parameter or the search-vectors command, and the error message does not always make that obvious.
  • Skipping normalization on embeddings. Cosine similarity assumes comparable vector magnitudes. If you generate embeddings without normalization, ranking quality degrades on catalogs with wide variance in text length.
  • Assuming SearchVectors supports range filters. Filter expressions work for equality and attribute-exists checks, not numeric ranges like price-between-X-and-Y. Filter those client-side after retrieving a larger TopK, or route the query to a different engine.

Troubleshooting DynamoDB Vector Search: 8 Issues and Fixes

Here are the errors you are most likely to hit while working through this tutorial or adapting it to your own catalog, along with what actually fixes each one.

SymptomLikely causeFix
“Unknown parameter: vector-indexes”AWS CLI predates the August 4, 2026 service modelRun pip install --upgrade awscli or update via your package manager
AttributeError on dynamodb.search_vectorsboto3 is on an older build without the vector operationsRun pip install --upgrade boto3 and restart your Python session
ValidationException: dimension mismatchQuery vector length does not match the index’s configured dimensionConfirm both use the same embedding model and dimension setting
Empty results with a valid query vectorVector index still initializing after table creationWait for describe-table to report the index status as ACTIVE before querying
ItemSizeLimitExceededException on PutItemEmbedding pushed the item past DynamoDB’s 400 KB limitMove large text fields to S3 and store only a reference, keep embedding on the item
Low-quality or irrelevant search resultsEmbeddings generated without normalization, or mixed model versionsRe-embed with normalize: True and confirm a single model version across the index
AccessDeniedException on SearchVectorsIAM policy missing the dynamodb:SearchVectors actionAdd the action explicitly; it is not covered by wildcard dynamodb:Get* policies
ThrottlingException during bulk loadOn-demand capacity briefly outpaced by a burst writeAdd exponential backoff around BatchWriteItem, or pre-warm capacity for large imports

Advanced Tips for Running DynamoDB Vector Search in Production

Once the basic pipeline works, a few adjustments separate a demo from something that survives real traffic.

Version your embeddings explicitly. Add an embedding_model_version attribute to every item so you can run a controlled migration when you eventually upgrade models, rather than discovering a silent mixed-version index months later. Batch your embedding calls to Bedrock where the model supports it, since invoking one item at a time adds latency you do not need during bulk loads. Cache query embeddings for common searches, since a user typing “waterproof jacket” repeatedly should not re-invoke Bedrock every time if you can serve a cached vector for a few minutes.

For write-heavy catalogs, separate your embedding generation from your write path using an SQS queue: write the item without the embedding first, then a background worker computes the embedding and updates the item asynchronously. This keeps your primary write path fast and isolates Bedrock latency spikes from user-facing writes. Finally, if your app needs both semantic search and traditional keyword search, do not force DynamoDB to do both. Run SearchVectors for the semantic path and a lightweight keyword index (even a GSI on a normalized text field) for exact matches, then merge results in your application layer.

The Complete Working Project: File Structure and Full Code

Here is the whole tutorial assembled into a small, runnable project. Save each block as shown and you have a working AWS vector database with a RAG endpoint on top of it.

vector-search-tutorial/
├── requirements.txt
├── embeddings.py       # get_embedding()
├── load_catalog.py     # put_product() loop over sample data
├── search.py           # search_products(), search_products_filtered()
├── rag.py              # answer_question()
├── benchmark.py         # benchmark_search()
└── setup/
    ├── vector-search-policy.json
    └── create_table.sh
# requirements.txt
boto3>=1.40.0
botocore>=1.40.0

Wire the pieces together in a small FastAPI endpoint and you have a semantic search API backed entirely by DynamoDB, with generation handled by Bedrock, and no second database in the stack.

from fastapi import FastAPI
from search import search_products
from rag import answer_question

app = FastAPI()

@app.get("/search")
def search(q: str, top_k: int = 5):
    results = search_products(q, top_k)
    return {"results": [{"name": r["name"]["S"], "score": r["SimilarityScore"]["N"]} for r in results]}

@app.get("/ask")
def ask(q: str):
    return {"answer": answer_question(q)}

When to Skip DynamoDB and Use a Different AWS Vector Database

This tutorial is not an argument that DynamoDB replaces every vector database use case, and treating it that way will burn you. Skip it when you need hybrid keyword-and-vector scoring in a single query, since SearchVectors does not blend the two the way OpenSearch’s k-NN plugin does — and OpenSearch extended that lead again when version 3.9 launched on September 29, 2026, adding 2-bit and 4-bit scalar quantization to shrink vector index footprints even further. Skip it when your corpus is a huge offline document lake measured in tens of millions of files rather than transactional items, since S3 Vectors, which reached general availability in December 2025 promising up to 40 times lower cost for large vector datasets, is purpose-built for that batch pattern at lower cost per vector. Skip it when you need Bedrock’s managed Knowledge Bases ingestion pipeline out of the box, since DynamoDB is not currently a supported target and you would be rebuilding chunking and sync logic yourself anyway.

Where it wins clearly: an app that already stores its operational data in DynamoDB, needs real-time semantic search or RAG retrieval on that same data, and wants to avoid the operational cost of a second managed service. That is a large share of production RAG apps built on AWS in 2026, which is why this feature drew attention the moment it hit general availability.

Frequently Asked Questions

Is DynamoDB vector search generally available now?
Yes. AWS announced general availability on August 5, 2026, with the feature live in all commercial AWS Regions and AWS GovCloud (US).

Does DynamoDB vector search cost extra on top of normal DynamoDB pricing?
Yes. On top of standard read/write capacity and item storage, vector search carries its own pay-as-you-go charges: vector index storage at $0.25 per GB-month, ingestion at $0.52 per GB written into a vector index, and $0.002 per GB processed and returned by SearchVectors queries (us-east-1 rates, billed per byte with a 1 KB minimum). It follows DynamoDB’s usage-based model, but these are dedicated line items rather than part of standard RCU/WCU pricing.

Can I use DynamoDB vector search with Amazon Bedrock Knowledge Bases?
Not as a native, managed target. Bedrock Knowledge Bases currently supports other vector stores for its automated ingestion pipeline. You can still use Bedrock embedding and generation models with DynamoDB, but you build the retrieval loop yourself, as shown in Step 9.

What is the maximum vector dimension DynamoDB supports?
4,096 dimensions, which covers virtually every commonly used embedding model, including Titan Text Embeddings V2 (1,024 dimensions), Cohere Embed, and OpenAI’s text-embedding models.

How does DynamoDB vector search compare to Pinecone on cost?
DynamoDB bills vector search on the same usage-based account as your tables, but it does carry dedicated vector charges (index storage at $0.25 per GB-month, $0.52 per GB ingested, and $0.002 per GB processed by SearchVectors), while Pinecone charges for dedicated pod size, RAM, CPU, and index storage as a standalone managed service. For teams already running DynamoDB, folding vector search into the same bill typically costs less than adding a second managed vector database, though the right answer depends on query volume and index size.

Does SearchVectors support hybrid keyword and vector search?
Not natively. SearchVectors runs pure ANN similarity search with basic equality filters. If you need hybrid keyword-plus-vector relevance scoring in a single query, use Amazon OpenSearch Service instead.

What AWS CLI and boto3 version do I need?
Any AWS CLI or SDK build that includes the DynamoDB service model update released August 4, 2026, or later. Run pip install --upgrade awscli boto3 if your tooling predates that date.

Can DynamoDB vector search handle a large product catalog?
AWS positions the feature as scaling to trillions of vectors because it inherits DynamoDB’s horizontal partitioning rather than running on a fixed-size cluster. AWS has not published exhaustive queries-per-second benchmarks, so benchmark your own workload with the method in Step 11 before committing to production scale.

For more cloud computing tutorials covering AWS, Azure, GCP, serverless, and Kubernetes, visit our cloud computing hub.

Sources: AWS What’s New: Amazon DynamoDB now supports real-time vector search, AWS Documentation: Tutorial – Your first vector search, AWS Database Blog: Build semantic search with native vector support in Amazon DynamoDB, AWS News Blog: Amazon DynamoDB now supports real-time vector search at any scale, InfoQ: AWS Introduces Native Vector Search for DynamoDB, and AWS DynamoDB Pricing.

Sofia Lindström

Sofia Lindström

Editor-in-Chief

Sofia Lindström is the Editor-in-Chief at Tech Insider, where she leads editorial strategy and oversees coverage across AI, cybersecurity, and enterprise technology. With over a decade in Swedish tech journalism, she previously served as technology editor at Dagens Industri and covered the Nordic startup ecosystem for Breakit. Sofia holds an MSc in Media Technology from KTH Royal Institute of Technology and is a frequent speaker at Web Summit and Slush. She is passionate about making complex technology accessible to business leaders.

View all articles