Milvus 3.0 vs 2.6: Lake-Native Vector Search Upgrade Guide 2026
Last Updated: September 24, 2026
For five years the contract of a vector database was simple: copy your data in, and it will search it fast. Milvus 3.0, which reached general availability on July 29, 2026, breaks that contract on purpose. Comparing Milvus 3.0 vs 2.6 is not a matter of a few new index types. Version 3.0 can index and search vectors that never leave your Iceberg, Parquet, Lance or Vortex tables. It adds a manifest-based storage engine called Storage V3 (“Loon”). And it moves sorting, aggregation, faceting and multi-stage reranking inside the server. The LF AI & Data Foundation calls it the largest architectural update in the project’s history. That is also why the upgrade deserves care. A 3.0 cluster can be rolled back to 2.6, but only until you switch on a feature that changes the on-disk format. After that, the only way back is a restore from backup.
What this covers: what 2.6 already gave you, what 3.0 adds at the storage and retrieval layers, how External Collections work over a lakehouse, the rollback trap, a staged upgrade runbook, failure modes, and a checklist.
Context and Background
Milvus is an Apache 2.0 licensed, graduated LF AI & Data project. Since its 2.x rewrite it has been one of the few vector databases built as a disaggregated, cloud-native system. Proxies accept requests, query nodes serve search, data nodes build indexes, and object storage holds the durable segments. If you want to see how it stacks up against managed and single-node alternatives on raw latency and recall, our 2026 vector database benchmark of Pinecone, Weaviate, Qdrant and Milvus is the place to start.
Milvus 2.6, released in June 2025, was a cost release. Its headline items were aimed squarely at the bill:
- Woodpecker, a diskless write-ahead log (WAL) that removed the need for an external Kafka or Pulsar cluster (both remain supported message queues).
- RaBitQ 1-bit quantization with SQ8 refinement. The vendor claimed a 72% memory reduction and 3x queries per second (QPS) at 95% recall.
- Streaming Nodes, dedicated to continuous ingestion.
- Tiered storage, splitting hot and cold data across SSD and object storage with lazy and partial loading. The vendor claimed up to 50% lower resource use.
- A MINHASH_LSH index for near-duplicate detection, although clients still had to compute the MinHash signatures themselves.
All of those features share one assumption: the data lives inside Milvus. You extract embeddings from your lakehouse, run an ingest job, and Milvus stores its own copy in its own segment format. That copy is the root of three recurring pains. It doubles storage for large corpora. It creates a freshness gap between the lake and the index. And it creates a governance gap, because the lake’s catalog, lineage and access rules do not follow the copy.
Meanwhile, the table-format world moved fast. Apache Iceberg became the default open table format for analytical data, and catalogs such as Polaris, Nessie and Unity compete to govern it. The official Milvus release notes frame 3.0 as the answer to that shift. A 3.0-beta shipped on May 9, 2026. GA followed on July 29, and patch releases 3.0.1 (September 9) and 3.0.2 (September 20) have since landed.
What Actually Changed: The Milvus 3.0 Reference Architecture
Direct answer: Milvus 3.0 differs from 2.6 in where data lives and where ranking happens. It can build indexes over lake tables in place (External Collections), adds a manifest-based storage engine (Storage V3), and runs sort, aggregation, facets and reranking server-side. Most new behavior is opt-in, so an upgraded cluster initially behaves like 2.6.

Figure 1: Milvus 3.0 reference architecture. The 2.6 path (Proxy, Streaming Node, Woodpecker, query and data nodes, internal segments) is intact; 3.0 adds opt-in Storage V3 manifests and External Collections that read lake tables in place.
The left half of the diagram is the Milvus you already run. Writes arrive at the Proxy, flow through a Streaming Node into the Woodpecker WAL, and are flushed by data nodes into internal segments on S3-compatible storage. The right half is new. Data nodes can now build indexes over files they do not own, and a second storage format sits beside the default one. Both paths end in the same object store, which is the point.
Pillar one: lake-native retrieval
An External Collection defines a Milvus collection over existing Parquet, Lance, Iceberg or Vortex files. It is zero-copy and read-only. Milvus maps columns to fields, builds its indexes (vector, BM25 full-text, JSON and scalar) over the external data, and keeps itself in sync through incremental refresh. One lake dataset can be served by several Milvus instances at once, which matters for teams that want a staging and a production cluster reading the same table.
Three GA additions make this practical rather than a demo. First, external fields can now feed function output fields. A text column in your Iceberg table can drive a server-side BM25 sparse vector, a MinHash signature or a text embedding, all built inside Milvus without copying the source. Second, refresh supports additive schema evolution. When the upstream table gains columns, Milvus patches the affected segments instead of rebuilding the collection. Third, a new milvus-table external format serves a Milvus Snapshot or a Storage V3 manifest as an external table. A collection snapshot can therefore become a source for another collection or a batch system.
The justification for this pillar is economic. If your embeddings already sit in the lake because a Spark job computed them, a second copy in Milvus buys you nothing except latency on the ingest path. Serving from the lake collapses the freshness gap to the refresh interval and keeps the lake as the single system of record.
Pillar two: Storage V3 (“Loon”)
Storage V3 is a manifest-based columnar storage engine on S3-compatible object storage. Each dataset version is an immutable, Avro-encoded manifest that lists the column groups, delta logs and statistics making up the dataset. Deletes are recorded as entity-level delta logs rather than by rewriting data files. Because the full state lives in object storage, the dataset is self-descriptive: any reader with access to the path can interpret it without a central catalog.
If this sounds like Iceberg, that is deliberate. It is the same design pattern (immutable snapshots, manifests, delete files) applied to a vector-plus-scalar workload. We covered the analogous mechanics, and why manifest trees matter for commit cost, in our breakdown of Apache Iceberg v4 vs v3 root manifests and single-file commits.
The practical payoff is point-read efficiency after an approximate nearest neighbor (ANN) search. The LF AI & Data announcement reports that in Milvus’s own internal benchmark, I/O per point read after ANN fell from about 9.4 MB with a Parquet baseline to about 0.07 MB, roughly 135x less. Treat that as a vendor figure, not a guarantee. The mechanism behind it is plausible, though. A Parquet row group is optimized for scans, so fetching one row can drag in a large compressed page. A manifest that knows column-group boundaries can fetch far less.
Storage V3 underpins Snapshots, TEXT fields and the milvus-table format. It is also disabled by default in 3.0, and enabling it is the step you cannot undo. We return to that below. One ambiguity is worth flagging now. The 3.0 release notes describe Storage V3 as the foundation for both Snapshot and External Collection, but the compatibility notes only name Snapshot and TEXT as needing common.storage.useLoonFFI. Confirm on a staging cluster whether your External Collection setup touches Storage V3 before you assume it leaves the rollback window open.
Pillar three: the retrieval engine moves server-side
The second LF AI & Data pillar is “a more powerful retrieval engine”. In 2.6, anything beyond top-k similarity with filters was your application’s problem. You over-fetched, then sorted, counted and reranked in Python. Version 3.0 pulls that work into the server:
- ORDER BY on Query and Search, across multiple fields, ASC or DESC per field.
- Query Aggregation with
group_by_fieldsand aggregate expressions inoutput_fields:count(*),count(<field>),sum,avg,min,max, evaluated server-side after filtering. - Search Aggregation, or faceted search, now GA. It returns top facet values, each represented by its best ANN match and annotated with COUNT or AVG.
- Function Chain reranking, an ordered, typed pipeline run inside a single search request (Figure 3).
The reason this matters is network amplification. Faceting a search client-side typically means fetching hundreds of candidates to count a handful of facet values. Doing it at the Proxy returns only the answer.
What 2.6 already had that 3.0 keeps
It is worth being precise about what did not change. Woodpecker is still the native WAL, and Kafka remains a supported option (patch 3.0.2 even fixes SASL/SCRAM authentication against Kafka 4.x brokers). In 3.0 Woodpecker can also run as a standalone service instead of being embedded in other nodes, for independent scaling and fault isolation. RaBitQ, tiered storage and Streaming Nodes carry forward. The upgrade is additive at the architecture level. What changes is the set of optional capabilities you can turn on, and some of those are one-way doors.
Deeper Walk-through: External Collections, Indexes and the Query Path
This section follows data through the new paths, then compares the two versions feature by feature.
The External Collection lifecycle

Figure 2: The External Collection lifecycle. A collection is defined over lake files, functions derive retrieval fields, indexes are built, and incremental refresh either indexes new files or patches segments when columns are added.
Read the diagram top to bottom. You start with a lake table that an upstream job already maintains. You define an External Collection over its files and map columns to Milvus fields: an embedding column to a vector field, IDs and attributes to scalar fields. Optionally, you attach functions so that Milvus derives BM25 sparse vectors, MinHash signatures or embeddings from text columns. Milvus then builds its indexes and starts serving.
The right branch is where operations happen. When the upstream job appends files, an incremental refresh indexes only the new data. When it adds columns, refresh takes the additive-schema path and patches affected segments. What refresh does not cover in 3.0 is just as important. The collection is read-only, so you cannot upsert through Milvus. Predicate pushdown for External Collections is on the roadmap, not in 3.0. Delta Lake and Apache Paimon formats are roadmap items too.
A worked example makes the trade-off concrete. Suppose a product-catalog team keeps 200 million items in an Iceberg table, with a 768-dimension float32 embedding per row. The raw vector payload is 200M x 768 x 4 bytes, about 614 GB (an estimate from simple arithmetic, before compression or quantization). In 2.6 you would ingest that into Milvus, storing it a second time alongside the lake copy and running an ingest pipeline to keep it fresh. With an External Collection the lake copy is the only copy of the raw columns. Milvus still stores its own indexes, and a quantized index is typically a fraction of raw size. The saving is the duplicated raw data plus the ingest pipeline, not the index.
How the index choices changed
The index story in 3.0 has four threads.
Sparse vectors got rebuilt. Version 3.0 introduces SINDI (described in arXiv 2509.08395), Block-Max WAND and Block-Max MaxScore, plus inverted-list compression, configurable quantization and per-workload algorithm selection. Milvus’s internal benchmarks claim the compressed BM25 index is about 3x smaller than the 2.6 sparse index at comparable recall. They also claim SINDI reaches up to about 10x the QPS of MaxScore on learned sparse embeddings such as SPLADE. Both are vendor numbers. Crucially, none of this activates on upgrade. You must raise dataCoord.targetVecIndexVersion to 10 and dataCoord.targetScalarIndexVersion to 4. After that, SINDI becomes the default for sparse inner-product search and MaxScore the default for BM25. The release notes add that a later release will enable the new index versions by default, so this opt-in window will not last forever.
Multi-vector entities arrived. StructArray, also called EmbList, stores a variable-length list of vectors per entity. This is the data model that late-interaction retrievers such as ColBERT and ColPali need, and it also fits documents split into chunks or multimodal records. It is indexed on disk with DISKANN, with Muvera and Lemur acceleration paths. GA added nulls, bitmap indexes, dynamic field addition and partial upsert. It also added element-level hybrid search with per-entity collapse (max, sum, avg or top-k), and filter quantifiers: element_filter, MATCH_ANY, MATCH_ALL, MATCH_LEAST, MATCH_MOST, MATCH_EXACT, positional access like tags[0][name] and array_length().
FAISS passthrough. A FAISS index type accepts any Faiss index-factory string through faiss_index_name, for example IVF64,Flat, HNSW16,Flat or OPQ16,IVF64,PQ16x4. If your research team tuned a Faiss recipe offline, you can now reproduce it in Milvus rather than approximating it with a native index.
Long text became first-class. TEXT fields support text_match, phrase_match and BM25. Values under 64 KB are stored inline. Larger values go to partition-level LOB files in Vortex format, and the column stores only a (file_id, offset) reference. Compaction moves references instead of rewriting text. For retrieval-augmented generation (RAG), that means the vector and its source passage can come back in one round trip, without a separate blob store.
The multi-stage query path

Figure 3: A search request with a Function Chain. Each QueryNode runs ANN recall, filters and L0 rescoring; the Proxy reduces shard results, calls an L2 reranker and applies ORDER BY before returning hits.
The sequence diagram shows why the Function Chain is more than syntax. A search fans out to QueryNodes, one per shard. Each QueryNode runs ANN recall with filters, then an L0 rescoring stage. That stage can be a native XGBoost model, stored as a UBJ file registered as a FileResource. Each shard returns its local top-k to the Proxy, which reduces and merges them. The Proxy then runs L2 post-reduction reranking, for example calling a Hugging Face Inference Provider model, and applies ORDER BY and trimming.
The split is a cost decision. L0 runs close to the data on many candidates, so it must be cheap: a gradient-boosted tree on a few features. L2 runs once on a small merged set, so it can afford a cross-encoder. In 2.6 you built this cascade yourself, paying a network hop for every candidate you wanted to rescore.
Here is an illustrative estimate of that saving. Say you rerank the top 200 of 8 shards, and each candidate returns 2 KB of fields. Client-side, every shard ships 200 candidates, so the client receives 8 x 200 x 2 KB, about 3.2 MB per query. With L0 trimming each shard to 25 before reduction, the Proxy handles 8 x 25 x 2 KB, about 400 KB, and the client gets only the final page. These numbers are assumptions chosen to show the shape of the saving, not a benchmark.
Online schema and TTL
Two smaller features change daily operations. Online schema changes let you add, backfill and drop columns while serving continues. External backfill means taking a snapshot as a consistent start point, computing values offline, and writing them back so Milvus indexes the new column incrementally. The release notes describe this as turning an embedding-model upgrade across hundreds of millions of rows into a no-downtime path. Inner backfill attaches a BM25 or MinHash function to an existing collection and computes its output over existing data. Adding a vector field also works online, provided the field is nullable=True; nullable vectors are supported on all six vector types.
Entity TTL is now driven by a TIMESTAMPTZ field, so expiry follows a business timestamp rather than insert time. Combined with the server-side MinHash function (FunctionType.MINHASH, VARCHAR in, BINARY_VECTOR out), 3.0 finally closes the 2.6 gap where MINHASH_LSH existed but you had to compute signatures in your own code.
Feature comparison table
| Capability | Milvus 2.6 | Milvus 3.0 | On by default after upgrade? |
|---|---|---|---|
| Data location | Ingested copy only | Ingested copy or External Collection over Parquet, Lance, Iceberg, Vortex | External Collections are opt-in per collection |
| Storage engine | Existing segment format | Adds Storage V3 manifests | No, needs common.storage.useLoonFFI |
| Snapshots | Not available | Point-in-time read-only views | No, depend on Storage V3 |
| WAL | Woodpecker embedded, or Kafka/Pulsar | Woodpecker embedded or standalone, or an external queue | Deployment choice |
| Sparse index | 2.6 sparse index | SINDI, Block-Max WAND, Block-Max MaxScore, compression | No, needs index version bump |
| MinHash | MINHASH_LSH, client-side signatures | Server-side MinHash function | Opt-in per schema |
| Multi-vector entities | Not native | StructArray with DISKANN | Opt-in per schema |
| Sort and aggregate | Client-side | ORDER BY, Query Aggregation, faceted search | Available via API |
| Reranking | Client-side cascade | Function Chain with L0 and L2 stages | Available via API |
| Long text | VARCHAR limits | TEXT fields with LOB files | No, depends on Storage V3 |
| Schema changes | Limited | Online add, backfill, drop | Available via API |
| Spark integration | External tools | Spark DataSource V2 connector | Separate component |
| GPU images | Earlier CUDA | CUDA 12.9, no Ubuntu 20.04 GPU support | Yes, image change |
| SDKs | 2.6.x line | 3.0.x line | Must upgrade |
The last column is the one to study. Almost nothing changes behavior on its own, and that is what makes a staged upgrade possible.
The Rollback Trap and a Staged Upgrade Runbook
The single most important sentence in the 3.0 compatibility notes is this: 2.6 to 3.0 compatibility and rollback are guaranteed, but once you enable or use features that change the serialized data format, such as Storage V3, rollback is no longer possible. Every planning decision below follows from it.

Figure 4: A staged Milvus 3.0 upgrade. Binary swap and soak stay reversible; raising index versions is treated as a gate; enabling Storage V3 is the point of no return.
The diagram separates the upgrade into three stages with different reversibility. Stage one swaps images and SDKs while data stays in the 2.6 format, so rolling back to 2.6 remains supported. Stage two opts into the new index versions and rebuilds. Stage three enables Storage V3, after which only a restore from backup gets you back to 2.6.
Why the trap is easy to fall into
The trap is not that Storage V3 is dangerous. It is that the features people upgrade for sit behind it. Snapshots require Storage V3. TEXT fields require it. So does the milvus-table external format. A team that upgrades “to get snapshots for A/B evaluation” will flip common.storage.useLoonFFI in the first week, often before the new binaries have soaked under production load. If a regression then surfaces, a rolling image downgrade will not work. They are restoring from backup under pressure.
There is a subtler version too. The release notes guarantee rollback only until you “enable or use” format-changing features. On a shared cluster, one team creating a TEXT field or snapshot on its collection can end the rollback window for everyone. Gate the flag with change control, not just a config review.
Is the index version bump reversible?
The release notes name Storage V3 as the example of a format-changing feature. They do not state explicitly whether raising targetVecIndexVersion to 10 blocks rollback. My working assumption, which you should verify against the official upgrade guide, is to treat it as effectively one-way. A 2.6 node has no code for the SINDI or compressed BM25 formats, so it is unlikely to load index files built at a version it does not recognize. In practice that means planning a rebuild on rollback, which for large sparse indexes can take hours. That is why Figure 4 puts the rollback exit before the index bump.
Stage one: binaries and SDKs (reversible)
- Read the official upgrade guide for your deployment method (Helm, Milvus Operator or Docker Compose). Minimum 2.6.x patch levels and chart versions are published there; this article deliberately does not guess them.
- Back up everything. Take a Milvus Backup of metadata and collections, and make sure object storage has versioning or a copy. This backup is your only exit after stage three.
- Pin SDKs to the 3.0.x line. The 3.0.0 matrix lists Python SDK 3.0.1, Node.js 3.0.3, Java 3.0.5 and Go 3.0.0. Patch 3.0.2 pairs with Python 3.0.2, Node.js 3.0.6, Java 3.0.10 and Go 3.0.2. Consider starting on 3.0.2 rather than 3.0.0, since it fixes data-correctness issues including an incomplete binlog chunk treated as fully read and incorrect results after a StructArray field was dropped and re-added.
- Check GPU hosts. GPU images moved to CUDA 12.9 and dropped Ubuntu 20.04 GPU compatibility. Upgrade host drivers and OS before the image swap, or GPU query nodes will not start.
- Swap images and soak. Run production traffic for a period you define up front, such as one full weekly traffic cycle. Compare p50 and p99 latency, recall on a golden query set, memory, compaction backlog and WAL lag against your 2.6 baseline.
A version-gate detail helps here. Patch 3.0.2 added a cluster-version gate that enables write-before function materialization only after all nodes finish upgrading, to avoid mixed-version inconsistency during rolling upgrades. That is a good sign for rolling upgrades, but it also means some behaviors change the moment the last node flips.
Stage two: index versions (treat as one-way)
The two keys are named in the release notes. In milvus.yaml terms they look like this; confirm the exact nesting against your chart’s values file:
dataCoord:
targetVecIndexVersion: 10
targetScalarIndexVersion: 4
After raising them, rebuild the indexes you care about, starting with a non-critical collection. Measure index size, build time, load time, recall and QPS against the 2.6 index on the same data. The vendor’s 3x size and 10x QPS figures are the ceiling you are testing, not a promise. Learned-sparse workloads such as SPLADE are where SINDI is claimed to shine; plain BM25 defaults to MaxScore.
Stage three: Storage V3 (point of no return)
Only enable common.storage.useLoonFFI when three things are true. You need a feature that depends on it (Snapshots, TEXT, milvus-table). The cluster has soaked cleanly through stages one and two. And a restore drill from your backup has succeeded within your recovery time objective. The release notes also say Storage V3 will be enabled by default in a later release. Plan for that now: read release notes before every future minor upgrade, so a default change does not end your rollback window for you.
Trade-offs, Gotchas, and What Goes Wrong
External Collections trade freshness for simplicity. They are read-only and refresh incrementally, so the index lags the lake by your refresh interval. If you need millisecond read-after-write, keep an ingested collection for the hot tail and an External Collection for the history. Without predicate pushdown (roadmap, not 3.0), filters are evaluated by Milvus over its indexed fields rather than pruned at the file level by the table format.
Schema evolution is additive only. Refresh patches segments when columns are added. Renames, type changes and drops upstream are not described as supported refresh paths, so treat them as rebuild events. An Iceberg schema change that looks harmless to your analytics team can break a serving collection. Put the serving collection in the table’s change review.
Two catalogs, one truth. Storage V3 datasets are self-descriptive and do not need a catalog. Your Iceberg tables do. That is convenient, but it means Milvus snapshots and Iceberg snapshots are separate timelines. If governance requires lineage from the lake catalog to the serving index, you will have to record the mapping yourself. Our comparison of Iceberg catalogs Polaris, Nessie and Unity covers what each catalog can and cannot track.
Server-side ranking moves cost, not removes it. L0 XGBoost scoring runs on QueryNodes, so a heavy model raises query-node CPU and tail latency for every tenant. L2 calls to Hugging Face Inference Providers add an external dependency, network latency and per-call cost to your search path. Budget timeouts and a fallback ordering.
Early-patch correctness bugs are real. The 3.0.2 notes alone include fixes for incorrect output fields when reading external table data, lost source file metadata when building segment manifests, and misaligned packed column indexes after Storage V2 compaction. None of this is unusual for a major release, but it argues for the latest patch and a golden-set recall check.
Vendor benchmarks are not your workload. The 135x I/O reduction, 3x smaller BM25 index and 10x SINDI QPS all come from Milvus’s internal benchmarks. Your dimensionality, filter selectivity and object-store latency will move the numbers.
Operational surface grows. A standalone Woodpecker, a Spark connector and FileResources for dictionaries and models are all new things to deploy, monitor and version. Woodpecker standalone matters most for large, write-heavy clusters; small clusters can stay embedded.
Practical Recommendations
My thesis is that Milvus 3.0 is best understood as two upgrades wearing one version number. The first is a conventional engine upgrade: better sparse indexes, multi-vector entities, server-side sort, aggregation and reranking. It is low risk and mostly reversible up to the index bump. The second is a storage-model change, from “Milvus owns a copy” to “Milvus indexes the lake”. That one reshapes your data platform and is one-way once Storage V3 is on. Most teams should take the first upgrade now and schedule the second as a separate project with its own design review.
Adopt External Collections first where the lake is already the system of record and freshness in minutes is acceptable: catalogs, document archives and knowledge bases rebuilt by batch jobs. Keep ingested collections for high-write, low-latency workloads. If you are still deciding whether a dedicated engine is worth it at all, our analysis of pgvector vs a dedicated vector database sets out where the break-even sits.
Upgrade checklist:
- [ ] Read the official upgrade guide for your deployment method; note minimum 2.6.x patch and chart versions.
- [ ] Full Milvus Backup plus object-storage versioning; restore drill passed within your RTO.
- [ ] SDKs pinned to the 3.0.x matrix that matches your server patch.
- [ ] GPU hosts ready for CUDA 12.9; no Ubuntu 20.04 GPU nodes.
- [ ] Golden query set with recall and latency baselines captured on 2.6.
- [ ] Soak on 3.0 binaries with the 2.6 data format for a pre-agreed window.
- [ ] Index versions raised on one non-critical collection first; size, QPS and recall compared.
- [ ]
common.storage.useLoonFFIchanges behind change control, approved only with a named dependent feature. - [ ] External Collection refresh interval and upstream schema-change process agreed with the lake owners.
- [ ] Timeouts and fallback ordering configured for L2 reranking calls.
Frequently Asked Questions
What is the main difference between Milvus 3.0 and 2.6?
Milvus 2.6 was a cost-focused release that assumed data lives inside Milvus, adding the Woodpecker WAL, RaBitQ quantization, Streaming Nodes and tiered storage. Milvus 3.0 is lake-native. It can index Parquet, Lance, Iceberg and Vortex files in place through External Collections, adds the manifest-based Storage V3 engine, and moves sort, aggregation, faceting and multi-stage reranking into the server. It also rebuilds the sparse index around SINDI and adds StructArray multi-vector entities. Most of these capabilities are opt-in after the upgrade.
Can I roll back from Milvus 3.0 to 2.6?
Yes, with a condition. The official compatibility notes guarantee that a 3.0 deployment can be rolled back to 2.6. That guarantee ends once you enable or use features that change the serialized data format, with Storage V3 given as the example. Snapshots, TEXT fields and the milvus-table format depend on Storage V3, so using them closes the window. After that, restoring from a backup taken before the change is the only route back. Treat the index version bump as one-way too, until the upgrade guide confirms otherwise.
Does Milvus 3.0 copy data from Apache Iceberg?
No, not for External Collections. An External Collection is a zero-copy, read-only definition over existing lake files, including Iceberg, Parquet, Lance and Vortex. Milvus builds its own vector, BM25, JSON and scalar indexes over that data, so index files are stored separately, but the raw columns stay in the lake. Incremental refresh picks up new files, and additive column changes patch affected segments. Predicate pushdown into the table format, and Delta Lake and Apache Paimon support, are roadmap items rather than 3.0 features.
What is Milvus Storage V3 (Loon)?
Storage V3, code-named Loon, is a manifest-based columnar storage engine on S3-compatible object storage. Each dataset version is an immutable Avro manifest listing column groups, delta logs and statistics. Deletes are recorded in delta logs without rewriting data files, and the dataset is self-descriptive, so any reader with storage access can interpret it without a central catalog. Milvus reports, from internal benchmarks, roughly 135x less I/O per point read after ANN versus a Parquet baseline. It is disabled by default and enabled with common.storage.useLoonFFI.
Do I need to rebuild indexes after upgrading to Milvus 3.0?
Not to keep running. Existing 2.6 indexes keep working after the binary upgrade, and the new algorithms are opt-in. To use SINDI, Block-Max WAND, Block-Max MaxScore and the compressed BM25 index, you raise dataCoord.targetVecIndexVersion to 10 and dataCoord.targetScalarIndexVersion to 4, then rebuild. After that, SINDI is the default for sparse inner-product search and MaxScore for BM25. Test on one collection first, comparing size, build time, recall and QPS against your 2.6 baseline before rolling it out widely.
Which SDK versions work with Milvus 3.0?
Clients must move to the 3.0.x SDK line. For the 3.0.0 server, the official matrix lists Python SDK 3.0.1, Node.js 3.0.3, Java 3.0.5 and Go 3.0.0. For the 3.0.2 patch, released September 20, 2026, it lists Python 3.0.2, Node.js 3.0.6, Java 3.0.10 and Go 3.0.2. Pin the SDK that matches your server patch, and upgrade clients in the same change window as the server. New APIs such as Function Chain, aggregation and StructArray filters require the 3.0.x clients.
Further Reading
- Vector database benchmarks 2026: Pinecone vs Weaviate vs Qdrant vs Milvus
- pgvector vs a dedicated vector database: where the break-even sits
- Apache Iceberg v4 vs v3: root manifests and single-file commits
- Iceberg catalogs compared: Polaris vs Nessie vs Unity
- Milvus release notes, v3.0.x (official)
- LF AI & Data: Milvus 3.0 goes lake-native
- Milvus 2.6 launch overview (milvus.io blog)
By Riju — about
