Skip to main content

VectorDB guide

This is the end-to-end walkthrough for VectorDB, the platform's managed vector-search service. It assumes only an account and a project, and it takes you from zero to a queryable index.

What VectorDB is

VectorDB stores embeddings — the long numeric vectors produced by an embedding model — and answers "which stored vectors are closest to this query vector?" in milliseconds. Use it for semantic search, retrieval-augmented generation (RAG), agent long-term memory, recommendations, and deduplication.

Use cases:

  • Semantic search over docs, tickets, or products.
  • RAG — fetch the most relevant passages from your own data to ground a language model's answer.
  • Agent long-term memory — the agent memory bank is built on top.
  • Near-duplicate detection — "have we answered a question like this before?"

You bring the vectors. VectorDB stores, indexes, and serves them; it does not run an embedding model for you.

Quick start: searchable index in five commands

# 1. sign in once
platformctl login

# 2. create a small demo index (4 dimensions, cosine distance)
platformctl vectordb create docs --dimensions 4 --distance cosine

# 3. insert two points
printf '%s' '{"points":[{"id":1,"vector":[1,0,0,0],"payload":{"tag":"alpha"}},
{"id":2,"vector":[0,1,0,0],"payload":{"tag":"beta"}}]}' \
| platformctl vectordb upsert docs --points -

# 4. query for vectors near [1,0,0,0], top 2
platformctl vectordb query docs --vector '[1,0,0,0]' --top-k 2

# 5. clean up when done
platformctl vectordb delete docs

The same flow in the Console is Data services → VectorDB → Create index, then the index's Query section. Step 3 has no console equivalent: the console does not write points, by design — see the walkthrough below.

Core concepts

  • An index is the named container. Every vector in it has the same width (dimension count) and distance rule.
  • Dimensions (width) are fixed at create time and must match every vector you write. Leave it unset and you get the width of the platform's own hosted embedding model, so an index fed by our /embeddings endpoint fits with nothing set. Set it explicitly only when you bring vectors from a different model. See Inference.
  • Distance is the similarity function: cosine, dot, or euclid. Pick once at create time.
  • A point is one vector, plus an optional id — an unsigned integer or a UUID string, nothing else — and an optional JSON payload, the metadata the filter language can see. Omit the id and the platform generates a UUID.
  • A query returns the top-k nearest points, each with a similarity score. top_k is per-request.
  • A filter narrows a query by payload fields — for example tag = 'alpha'. It is not a full query language.
  • The index is scoped to your project and invisible to other projects. Two projects can both have an index named docs.
  • Index state moves pendingready → (degraded on failure). ready is the only state that accepts queries.
  • Vector writes are idempotent on id: re-inserting the same id replaces the vector and payload.
  • A query against an unreadied index returns an error; poll get until ready: true.

API examples

export VDB="https://api.codyhill.dev"
export PROJ="$(platformctl projects list -o json | jq -r '.[0].id')"
export TOK="<session token or API key>"

Create an index (platform default width, cosine):

curl -sX POST "$VDB/v1/projects/$PROJ/indexes" \
-H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"name":"docs","distance":"cosine"}'

Upsert points:

curl -sX POST "$VDB/v1/projects/$PROJ/indexes/docs:upsert" \
-H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"points":[{"id":1,"vector":[...],"payload":{"tag":"handbook"}}]}'

Note the :verb suffix. Writing and searching are custom methods — a literal :verb on the end of the index path, always with POST. There is no path-segment or query-parameter form; /indexes/docs/upsert matches no route and comes back 404.

Query top-5 with a payload filter:

curl -sX POST "$VDB/v1/projects/$PROJ/indexes/docs:query" \
-H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"vector":[...],"top_k":5,"filter":{"must":[{"key":"tag","match":{"value":"handbook"}}]}}'

CLI examples

platformctl vectordb list # all indexes in the project
platformctl vectordb get docs # state, dimension, distance, point count
platformctl vectordb create docs --distance cosine
platformctl vectordb upsert docs --points @points.json # accepts literal, @file, or - for stdin
platformctl vectordb query docs --vector @vec.json --top-k 10
platformctl vectordb delete-points docs --ids 1,2 # remove specific points
platformctl vectordb delete docs # drop the index

Console walkthrough

  1. Open the Console, pick your project.
  2. Go to Data services → VectorDB.
  3. Click Create index. Set Dimensions to match your embedding model and Distance to cosine unless you have a reason not to.
  4. When the new index flips to Ready, open it.
  5. The Data section browses the points already in the index — id and payload, a page at a time — and each row can be deleted. The Query section takes a vector and a Top K and shows results with scores; Fill with a random vector smoke-tests that the index answers at all. The console deliberately does not insert points: embeddings belong in your code, not a textarea. Use platformctl vectordb upsert or the API.
  6. The Payload filter field in the Query section accepts the same JSON filter language as the API.
  7. Delete index permanently drops the index and all points.

Limits and quotas

The VectorDB service enforces these at the API:

LimitDefault
Max points per upsert request1000
Max request body size32 MiB
Max top_k per query1000
Max dimension countbound by your embedding model; request body cap is the effective ceiling

If you hit a body-size error, split a bulk upsert into batches of 1000 points or fewer.

There is no enforced ceiling on indexes per project. Each index is a separate collection with its own memory footprint, so many small indexes cost more than one large one. One related bound does exist: a direct-access credential enumerates at most 256 collections per token and reports truncated: true beyond that.

Troubleshooting snippets

SymptomFirst thing to check
Query returns "index not ready"platformctl vectordb get docs — poll until state: ready and ready: true.
Upsert returns "vector dimension mismatch"One of your vectors is not the index's declared width. Every point in one index must be the same width.
Empty result set on an obvious matchYour query vector is in a different dimension space than the indexed vectors — same model, or the numbers will not be comparable.
Filter matches nothingThe payload key is case-sensitive and must match exactly; Tag and tag are different keys.
Error "top_k exceeds maximum"Lower --top-k to 1000 or fewer.
Bulk upsert is slowSplit into 1000-point batches. Run batches in parallel from the client; the service is built to absorb concurrent writes.
Delete worked but storage still shows in usageDeletion is asynchronous; the underlying collection drains within a few minutes.

Security notes

  • Indexes are project-scoped by construction. The API takes a project id on every call, and the service resolves that to the storage collection behind the index. No cross-project index is possible.
  • Bearer tokens gate both data and control plane. The same credential that creates an index is the one that upserts and queries. Rotate it like any other credential.
  • Direct-access credentialsGET /v1/projects/<id>/vectordb/credentials, project admin only — returns the low-level connection details for a client that would rather address the index storage directly than go through this REST API: service_url (a private address, reachable only from workloads in your project), collection_prefix, the exact collections covered, and — only when the platform has per-project JWT enforcement turned on — a time-limited token scoped read-write to those collections. Because it is read-write over every index in the project, it belongs in trusted server-side code, never in a browser. It is also a snapshot: an index created after the token was minted is not covered until you fetch credentials again. An address reachable from outside the platform (external_service_url) appears only when a token was issued and your project has published its vector database as an endpoint; otherwise the field is absent.
  • Payload content is your responsibility. VectorDB does not classify, redact, or audit JSON payloads — do not embed Personally Identifiable Information unless you have a policy reason to.
  • Query results are not logged by the service, but they are returned over TLS and can be captured anywhere your client runs. Treat the query log in your own application with the same care as the data itself.

Where next