
DynamoDB Got Native Vector Search. I Verified It, Day One
DynamoDB shipped native vector search on 2026-08-05. I checked the real API in the SDKs, built a live matching app, and hit an actual OIDC bug in production.
On 2026-08-05, AWS announced that Amazon DynamoDB now supports native vector search — no more copying data into a separate vector store, no more sync pipeline to babysit. I read the announcement post the same day someone forwarded it to me, and the first thing I noticed was that it had no code samples. Just prose: a
List attribute for embeddings, a SearchVectors API, single-digit millisecond latency, 99%+ recall. No parameter names, no SDK version, nothing I could actually run.So before writing anything, I went and checked whether the API was real.
Checking the SDKs directly, not the blog post
aws dynamodb help on my installed CLI (2.35.15) showed nothing vector-related. boto3 wasn't even installed locally. So I set up a clean virtualenv, installed the latest boto3/botocore, and asked the service model directly instead of guessing:1
2
3
4
5
import botocore.session
s = botocore.session.get_session()
model = s.get_service_model('dynamodb')
[o for o in model.operation_names if 'vector' in o.lower()]
# ['SearchVectors']It's there —
botocore 1.43.64 has it. I did the same check on the JS side, since the app I wanted to build would run on Vercel:1
2
3
npm view @aws-sdk/client-dynamodb version # 3.1103.0
find node_modules/@aws-sdk/client-dynamodb -iname "*SearchVectors*"
# SearchVectorsCommand.d.ts is there tooThen I dumped the actual input/output shape from the service model instead of trusting a blog summary:
CreateTablegained aVectorIndexeslist:IndexName,VectorAttribute.AttributeName,SearchSchema(aHASHelement plus optionalINLINE_FILTERelements),Projection,Dimensions,DistanceFunction(COSINE/EUCLIDEAN/DOT_PRODUCT).SearchVectorstakesTableName,IndexName,SearchVector(a list ofAttributeValue, i.e. the sameList<Number>shape as a regular item attribute),TopK, and an optionalSearchConditionExpressionwithExpressionAttributeNames/Valuesfor filtering.
One thing I checked and got a genuinely useful negative result on:
AWS::DynamoDB::Table in CloudFormation does not have a VectorIndexes property yet.1
2
# describe-type output for AWS::DynamoDB::Table, one day after GA
'VectorIndexes' in schema['properties'] # FalseIf your infra is CloudFormation-first, you can't provision a vector index through it right now — you have to reach for
boto3/CLI directly, which is a real limitation worth knowing about before you commit to an IaC plan.Building something real: Resonance Match
I didn't want to just curl an API and call it verified, so I built a small app: an icebreaker tool for conferences. You type a nickname and a sentence about what you're currently thinking about or building, it embeds your sentence with Bedrock and stores it in DynamoDB, then runs a live
SearchVectors query to find the semantically closest other people in the same room, refreshing every six seconds.
Table design:
- Partition key
eventId, sort keyattendeeId - A vector index scoped to the room:
SearchSchemahas oneHASHelement oneventId, so a search never crosses rooms Dimensions: 1024,DistanceFunction: COSINE— matching Bedrock'samazon.titan-embed-text-v2:0, which I confirmed returns 1024-dim vectors with a realinvoke-modelcall before hardcoding anything
Before writing the app, I ran the whole pipeline by hand with three fake attendees:
1
2
3
0.3638 "AI エージェントに承認ゲートをつける仕組みを作っています" (approval gates for AI agents)
0.4453 "生成AIエージェントの権限設計と人間承認フローに興味があります" (permission design + human approval)
0.8907 "週末は登山とキャンプが趣味です" (hiking and camping)Queried against "I want to talk about autonomous execution and approval design for AI agents," the two approval-gate sentences came back closest, the hiking sentence came back furthest. That's the moment I actually trusted the feature — not the blog post, this printout.
One gotcha in that printout: with
COSINE, the score is a distance, not a similarity. 0 means identical, 2 means opposite, and results are sorted ascending — lowest score wins. I initially misread 0.36 as "36% similar" before checking the JS SDK's doc comment, which spells it out explicitly. The conversion I ended up using: similarity% = (1 - score / 2) * 100.The bug that actually happened in production
Local dev worked immediately —
fromNodeProviderChain() picked up my aws login session, and the app matched people correctly on localhost. Production did not.First deploy: every
POST /api/join came back 500. Vercel's logs:1
Error [CredentialsProviderError]: Could not load credentials from any providersMy code read
process.env.VERCEL_OIDC_TOKEN and fell back to fromNodeProviderChain() if it was missing — the same pattern I'd used successfully in an earlier project. I checked whether OIDC Federation was actually on for this project:1
2
3
curl -s "https://api.vercel.com/v9/projects/resonance-match?teamId=$TEAM" \
-H "Authorization: Bearer $TOKEN" | jq .oidcTokenConfig
# {"enabled": true, "issuerMode": "team"}Enabled. And yet a debug endpoint I added confirmed
VERCEL_OIDC_TOKEN was simply not present in process.env at runtime. The token isn't statically injected the way I assumed — it has to be fetched through Vercel's own SDK. Switching from a hand-rolled fromWebToken() call to the official @vercel/oidc-aws-credentials-provider package fixed it in one line:1
2
3
4
5
import { awsCredentialsProvider } from "@vercel/oidc-aws-credentials-provider";
const credentials = process.env.AWS_ROLE_ARN
? awsCredentialsProvider({ roleArn: process.env.AWS_ROLE_ARN, roleSessionName: "resonance-match-web" })
: fromNodeProviderChain();Redeployed, tested with
curl first (to rule out anything browser-side), then with two real browser sessions submitting different sentences — both matched correctly, at a 73% similarity score, updating live within the six-second poll window.What I didn't verify
I want to be direct about the edges of this, since the whole point of the exercise was not overclaiming:
- No real event, no concurrent load. Two browser tabs is not a conference room.
PAY_PER_REQUESTthrottling behavior under a real spike is untested. - No content moderation on the free-text input. Fine for a personal demo, not fine for an unsupervised public room.
INLINE_FILTER— the equality-only filter attribute inSearchSchema— is implemented in the API but I never exercised it. My filtering is just theHASHelement oneventId.- No cost comparison against the existing OpenSearch zero-ETL path. I don't know yet whether native vector search is actually cheaper at scale, only that it removes a moving part.
- This is one day of production experience with a feature that is one day past GA. I'd treat anything here as "worked for me, once" rather than a stability claim.
Code is on GitHub , the app is live at resonance-match.vercel.app — bring a room full of people and a room code, and it'll tell you who in the room is thinking about the same thing you are.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article