Memory infrastructure
for AI agents.
In your own object storage.
A vector + hybrid search database that lives in your own object storage. Your bucket, your account, your VPC. A memory an agent writes on one step is durable, ordered, and readable on the next; the serving nodes are stateless caches you can add or remove at any time, so you pay for search and storage on your own terms.
A consistency contract
In the storage-backed deployment, a write is acknowledged only once it's durable in your bucket's log, in one order per collection, and readable by the very next query, even cold. One documented exception, stated in the same breath: a document's text becomes BM25-searchable at the next segment flush, seconds later, while vector search over that same write is immediate. How each guarantee works →
Your bucket is the database
Data, indexes, and the write log live in a bucket you own, under your IAM policies and encryption keys. That bucket can be AWS S3, GCS, Azure Blob, MinIO, or R2. Nothing leaves your account, and leaving costs nothing: your data is already yours.
Search three ways
By meaning, by keyword (BM25), or both fused in one query. Answers come straight from object storage when data isn't hot, so you don't pay RAM prices for data you rarely touch.
Disposable nodes
Serving nodes are stateless caches: kill any of them and lose nothing, add more when traffic spikes, tear them all down when it stops. A collection costs nothing while it sleeps.
Start on a laptop, graduate to a cluster
Day one is one small binary. No Docker, no config, and it's running in seconds. When you outgrow one machine, the same data model moves to nodes pointed at your bucket. Get started with the Go and Python clients →
Pick your speed–memory trade-off
Three interchangeable index types: fastest-in-RAM, a balanced default, or compressed to fit ~32× more vectors in the same memory. Switching is automatic and needs no downtime, because rebuilt indexes are swapped in atomically.
Quick start
Run a node, put a vector, and search it. Collections are auto-created
from the first vector's dimension, over plain HTTP or the Python SDK.
When you want your data to survive anything, add one flag: -store points the
node at your bucket and it takes care of the rest. Full setup, including the Python
client and the other ways to run it, is in the Get started guide.
# run a node (HTTP + gRPC); in-memory, zero config ./polign-server # durable? one flag — your bucket becomes the source of truth # ./polign-server -store s3://my-bkt/polign # put a vector — the collection is auto-created curl -X PUT localhost:23000/v1/collections/docs/vectors/a \ -d '{"values":[1,0,0],"metadata":{"label":"first"}}' # search by nearest neighbour curl -X POST localhost:23000/v1/collections/docs/query \ -d '{"values":[0.9,0.1,0],"k":5}' {"hits":[{"id":"a","distance":0.02,"metadata":{"label":"first"}}]}
# pip install polign — pure-stdlib HTTP client, zero dependencies from polign import Client client = Client("http://localhost:23000") # upsert — the collection is auto-created client.put("docs", "doc-1", embedding, metadata={"title": "Cats"}) # nearest-neighbour search — smaller distance = closer for hit in client.search("docs", values=query_embedding, k=10): print(hit.id, hit.distance, hit.metadata) # same API over gRPC: pip install "polign[grpc]" # from polign import GrpcClient; client = GrpcClient("localhost:23001")
Feature set
The full feature set ships in one server binary, with no tiers and no add-ons.
- Vector search — three index types, fastest to most compact
- Keyword search — BM25 built in, served from your bucket
- Hybrid search that blends meaning and keywords in one query
- Metadata filters — exact match, lists, ranges, and combinations
- API-key auth with bearer keys guarding management calls
- gRPC + HTTP/JSON — same operations either way
- One static binary — no Docker, no dependencies to run
- Clients — Go package and Python SDK
- Your cloud's object store — S3, GCS, Azure Blob, MinIO, R2
- Durable write log — in your bucket, no Kafka
- Batch upserts — up to 5,000 vectors per call
- Cold search — straight from the bucket, no RAM index
- Read-your-writes — immediate for vector search even on cold reads; BM25 text at the next flush
- Disk cache tier — optional NVMe between RAM and S3
- Zero-downtime rebuilds — atomic index swap-in
- ~32× compression — compressed vectors, accuracy re-checked
- Scale to zero — stateless, disposable nodes
Benchmarks
Every number below was measured with polign_db's benchmark harness on standard EC2 instances against local disk, MinIO, and same-region Amazon S3. Accuracy is recall@10, which is how many of the ten true nearest neighbours each search returns. The full methodology and every configuration are on the benchmarks page.
| Scenario | Measured result |
|---|---|
| Search from memory — 1M vectors, 128-dim (SIFT1M) | 2,860/s @ 96.5% recall · 950/s @ 99.4% |
| Search from memory — 100M vectors, 128-dim (16-vCPU machine) | 869/s @ 95.5% recall |
| Cold search, no index in RAM — same-machine store | 18 ms typical · 27 ms p99 @ 98% recall |
| Cold search, no index in RAM — Amazon S3, same region | ~144 ms typical · ~354 ms p99 |
| Cold search at scale — 100M vectors, straight from S3 | 91.6% recall @ 385 ms typical |
| Writes through the S3 log — durable before acknowledged | ~6,200/s per log @ ~161 ms typical · ~286 ms p99 |
| Compressed index (IVF-PQ) — 100M vectors, 16× smaller | 98.8% recall with re-check · ~300/s |
The comparisons with Qdrant, Weaviate, Milvus, and turbopuffer are spelled out on the benchmarks page, including where they are faster, with the multipliers stated plainly.
Point it at your bucket.
Install the server and bring your own S3.