All comparisons
Comparison

milvus vs pgvector: a distributed vector service against an extension inside Postgres

Milvus is a separate system built for horizontal scale, streaming updates and a Kubernetes deployment, while pgvector puts a vector column into the Postgres you already run and keeps JOINs, transactions and point-in-time recovery. The choice is about where your vectors live relative to the rest of your data.

Published October 22, 2026

At a glance

Projectmilvus-io/milvuspgvector/pgvector
LicenceApache-2.0Permissive: commercial use allowedCustom licenceCustom licence: read the LICENSE file
MaintenanceCommits in the last dayLast push October 23, 2026Commits in the last dayLast push October 23, 2026
LanguageGoC
GitHub stars46,46123,454
Read moreOur analysisGitHubOur analysisGitHub

Star history

  • milvus-io/milvus46,461 ★ · +1,059
  • pgvector/pgvector23,454 ★ · +336
Star history
Repository2026-07-282026-10-23
milvus-io/milvus45.4k46.5k
pgvector/pgvector23.1k23.5k

Open the full Star history comparison

Which one to choose

milvus

Choose milvus if you need a vector service that scales horizontally, takes real-time streaming updates, and runs on Kubernetes with replicas and query nodes you can grow separately from writers. Choose it when the index is infrastructure with its own operators, not a column in a table you already own.

pgvector

Choose pgvector if your vectors belong beside relational rows in a Postgres database, so that a JOIN, a transaction and a point-in-time restore all happen in one place. Choose it when adding a separate distributed system would cost more than the scale you need.

A service in Go and C++ against a C extension inside Postgres

The two projects differ less in what they store than in where the storing happens.

Milvus is a system of its own. Its README describes it as a vector database written in Go and C++ with a fully distributed, Kubernetes-native architecture, and it says the system can scale horizontally, handle tens of thousands of search queries on billions of vectors, and keep data fresh with real-time streaming updates. The distributed architecture separates compute from storage, so you can add query nodes for a read-heavy workload and data nodes for a write-heavy one, stateless microservices on Kubernetes give quick recovery from failure, and replicas load data segments onto several query nodes at once. Milvus also stores vectors together with scalar types such as integers, strings and JSON objects, and its query layer offers metadata filtering and hybrid search.

pgvector is an extension. It adds a vector type, six distance operators and two approximate index types to a Postgres server, and the README lists what that buys you: ACID compliance, point-in-time recovery, JOINs and the rest of Postgres. There is no new service to deploy. You compile a shared library and load it into the database you already run.

So the bargain is proximity against scale. In Milvus the vectors sit in Milvus's own storage and are reached over the network through the pymilvus SDK. In pgvector the vector column is a column in your table, and selecting neighbours next to your orders rows is one statement inside one transaction.

Installing Milvus Lite and building pgvector from source

The two installation paths are not comparable in effort, and the reason is that one of them has to compile code.

Milvus starts as a pip install. The README quickstart is `pip install -U pymilvus`, then `from pymilvus import MilvusClient`, and a local database is one line: `client = MilvusClient("milvus_demo.db")`, with Milvus Lite installed through `pip install pymilvus[milvus-lite]`. From there the documented calls are create a collection with a dimension, insert rows, and search with a top-k limit and a list of output fields. Going beyond a laptop means choosing a deployment: Standalone mode for a single machine, the distributed architecture on Kubernetes, or Zilliz Cloud, which the README lists as Serverless, Dedicated and BYOC options.

pgvector needs a Postgres 13 or newer server and either a compiler or a package channel. The README's Linux and Mac route is a clone of the v0.8.6 tag, then `make` and `make install`. It also lists Docker, Homebrew, PGXN, APT, Yum, pkg, APK and conda-forge, and notes that the extension comes preinstalled with Postgres.app and with many hosted Postgres providers. On Windows the build uses `nmake` against Makefile.win. Once installed, `CREATE EXTENSION vector` enables it per database, a column is declared as `embedding vector(3)`, and neighbours come back with `SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5`. The distance operators are L2 with `<->`, negative inner product with `<#>`, cosine with `<=>`, L1 with `<+>`, Hamming with `<~>` and Jaccard with `<%>`.

A pip install and a compiler in the same morning is the practical difference.

Two index families and one honest note about recall

Both projects offer an exact option and an approximate one, and both expect you to choose.

pgvector searches exactly by default, and the README says that default provides perfect recall. Adding an index switches on approximate nearest neighbour search, which trades some recall for speed, and the README is unusually candid about the consequence: unlike typical indexes, you will see different results for queries after adding an approximate index. Two index types are supported, HNSW and IVFFlat. HNSW creates a multilayer graph, has the better query performance of the two in terms of the speed and recall trade-off, but slower build times and more memory, and it can be created on an empty table because, unlike IVFFlat, it has no training step. An index is added per distance function, `CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)`, with `halfvec_l2_ops` and `sparsevec_l2_ops` for the half-precision and sparse types. The supported vector types are single-precision, half-precision, binary and sparse.

Milvus covers the main index families too: its README lists HNSW, IVF, FLAT for brute-force search, SCANN and DiskANN, along with quantization-based variants, with each tuned for a different scenario. Milvus also adds hybrid search and metadata filtering to the query itself, where pgvector's filtering story is the ordinary Postgres story of a WHERE clause alongside the ORDER BY.

The operational consequence of the recall difference is the same in both: an approximate index changes what comes back, so results before and after are not comparable.

Query nodes and replicas against the Postgres you already run

Scaling and operating are where the two are furthest apart, and the gap is larger than the query path suggests.

Milvus is designed to be operated as a cluster. The README describes stateless microservices on Kubernetes for quick recovery from failure, replicas that load data segments onto multiple query nodes for fault tolerance and throughput, and independent growth of query nodes for read-heavy traffic and data nodes for write-heavy traffic. That is a real operational surface: a cluster to schedule, a dependency order to respect, and a deployment to reason about when something is unhealthy.

pgvector adds no new process. It rides on the Postgres instance you already have, with the instance's own backup, replication and failover story, and its scaling limit is the limit of one server and one table.

There is a second operational difference that is easy to miss and expensive to discover late. pgvector's default build is tuned with `-march=native`, so an extension compiled on one machine is not portable to an older CPU, and the compile options relax floating point semantics, so distances are not reproducible across different build flags. Our analysis of pgvector calls this out directly, and the fix is one documented switch, `make OPTFLAGS=""`, which the Dockerfile and the portability note in the Makefile already use. Our analysis of milvus gives the matching check from the other direction: confirm that your deployment environment can handle the operational overhead of the distributed mode, and verify your exact index type, GPU support and multi-tenancy isolation level against the current documentation.

Where milvus falls short

Milvus's own analysis tells you when to stay away: avoid it if your workload is a small prototype where Milvus Lite or a simpler tool suffices. That is the honest version of the warning, and it applies more often than the marketing suggests, because Milvus ships two other things alongside the cluster. There is Milvus Lite for a local file, and there is Zilliz Cloud in Serverless, Dedicated and BYOC forms, and either of those can be the right answer for a team that has no interest in running a distributed vector service.

The cost of the cluster itself is the other limit. A separate system means a separate deployment, a separate upgrade path, its own monitoring, and vectors that no longer join with the tables in your primary database without an extra hop. When your retrieval query needs rows from Postgres, the network round trip between two systems becomes part of every request.

The release lines add a smaller wrinkle. The repository's recent tags include v3.0.0 on 2026-07-29 and, on the older line, v2.6.22 on 2026-08-04 and v2.6.23 on 2026-08-28, so a new major version and patch releases on the previous line are moving at the same time. That is normal for a project with this much adoption, and it is still a decision about which line you run and how quickly you move.

Where pgvector falls short

pgvector's limits are the price of putting the vectors in a table.

The first is scale. There is one server and one index, so the horizontal growth story that Milvus is built around is not available here, and the default exact search with perfect recall becomes the thing you give up when the table grows past what a sequential scan can serve. The second is multi-tenancy. Isolation has to be assembled from Postgres roles, schemas and row-level policies, which is workable but is not a feature with its own configuration surface and its own documentation.

The third is packaging. The repository has no GitHub releases, so the version you run is the tag you cloned or the branch you tracked, and pinning means doing it yourself. The fourth is the build portability problem already described: `-march=native` by default, floating point semantics relaxed by the compile options, and a machine fleet that is not uniform enough for that to be safe.

The fifth is quieter and worth stating plainly. Because an approximate index changes results, a pgvector setup can look like a regression when someone adds an HNSW index to fix a latency problem and the neighbour set shifts. The README says it plainly enough, and the fix is to know it is coming.

Licences, maintenance and the choice for concrete situations

Milvus is Apache-2.0, distributed under the LF AI and Data Foundation with Zilliz as its major contributor. For pgvector, GitHub cannot classify the licence and points at the LICENSE file instead, so read that file rather than assuming what a Postgres extension usually carries. Both repositories had their last push on 2026-10-21, so neither is dormant, and Milvus publishes tagged releases while pgvector does not.

The concrete situations separate cleanly.

Your embeddings sit in a table beside orders, tickets or documents, and your query needs a JOIN. pgvector, because the vector column and the relational columns live in one database and one transaction.

You need the vectors to be transactionally consistent with the rows they describe. pgvector, for the same reason, and ACID compliance is not something you have to reconcile.

Your collection is in the tens of millions and you need read and write capacity to grow independently. Milvus, with query nodes and data nodes scaled separately and replicas for fault tolerance.

Your documents arrive continuously and must be searchable immediately. Milvus, whose README calls out real-time streaming updates as a design point.

You want hybrid search and metadata filtering as part of the query language rather than assembled by hand. Milvus.

You need isolation per customer as a product feature with its own admin surface. Milvus, where multi-tenancy is built in and can be checked against the documentation.

You want vector search on a laptop today with no database at all. Milvus Lite through `pip install pymilvus[milvus-lite]`, or pgvector against a local Postgres if you already run one.

Your team has no Kubernetes and no on-call rotation for a data service. pgvector, because there is nothing new to page anyone about.

Your build machines are a mixed CPU fleet and you ship the extension to production. pgvector, with `make OPTFLAGS=""` applied deliberately and a pinned Postgres major version.

Before committing to milvus, check your index type, GPU support and multi-tenancy isolation level against the current documentation. Before committing to pgvector, check how the production extension is built, since that single switch decides whether the binary you ship runs on the hardware you have.

Bottom line

Milvus is the right choice when the vector index has to be a system in its own right, because its architecture separates query nodes from data nodes, loads segments onto replicas and takes streaming updates without slowing readers down; pgvector is the right choice when the vectors are part of a business record, because a vector column in your own table gives you JOINs, transactions and point-in-time recovery without a second system to secure. Verify first, for milvus, that your index type, GPU support and multi-tenancy isolation level match the current documentation and that your environment can carry the distributed mode, for pgvector, that the production extension is built with `make OPTFLAGS=""` and against a pinned Postgres major version, since that decision is what determines whether the binary runs on the hardware you have. The judgement worth keeping is that Milvus buys scale with a second system to operate, while pgvector buys proximity with a single server to grow, so the question to ask first is which of those two costs you can actually pay.

Sources

  1. milvus-io/milvus repository
  2. milvus-io/milvus README
  3. pgvector/pgvector repository
  4. pgvector/pgvector README

Was this useful?