This guide is for engineers, architects, and operators who build Faiss from source, embed it in a service, tune it for production, or harden it against untrusted input. It documents Faiss v1.14.2 as a system: its architecture, build configuration, runtime dispatch, persistence format, security posture, and internals — at a depth sufficient for an AI or human to reason about, deploy, or extend the library without consulting other sources.
For the end-user API (how to build and query indexes from Python), see the User Guide. This document does not repeat that material; it links to it.
Table of Contents
- Executive Summary
- Architecture
- Repository Structure
- System Requirements
- Building from Source
- Build Configuration Reference
- Runtime SIMD Dispatch
- The Index Class Hierarchy
- Persistence & I/O
- Security
- GPU & Accelerator Backends
- Operations & Scaling
- Performance Tuning
- The C API
- Code Quality & Conventions
- Testing
- Potential Improvements & Known Issues
- Quick Reference
1. Executive Summary
Faiss is a C++17/C++20 library for similarity search and clustering of dense vectors, with complete SWIG-generated Python bindings and an optional C API. Its single architectural abstraction is the Index: an object that stores vectors and answers nearest-neighbor queries. Everything else — inverted files, product quantization, graph indexes, GPU acceleration, preprocessing transforms — is a concrete Index subclass or a wrapper composing other indexes.
Key architectural facts:
- Language: C++ core (only hard dependency: a BLAS implementation). Python bindings via SWIG over NumPy. Optional C API.
- Compute backends: CPU (with runtime SIMD dispatch across AVX2/AVX512/AVX512-SPR/SVE/RVV), NVIDIA GPU (CUDA, optionally via NVIDIA cuVS), AMD GPU (ROCm), and Apple Silicon (Metal,
IndexFlatonly as of v1.14.2). - No daemon, no network surface. Faiss is linked into your process. It is not a server; it has no listening sockets, no authentication, and no built-in access control. Security concerns are about the data you feed it (training vectors, queries) and the index files you deserialize.
- Persistence: any index serializes to a single file via
write_index/read_index, with flags for read-only, memory-mapped, and on-disk loading. - Build system: CMake. Distributed as conda packages (
faiss-cpu,faiss-gpu,faiss-gpu-cuvs) and, as of v1.14.2, pip wheels.
Note
Because Faiss runs in-process, "deployment" means deciding how your service builds, loads, and queries indexes — and how it isolates that work. There is no Faiss service to operate, monitor, or patch independently of your application.
2. Architecture
Layered view
┌──────────────────────────────────────────────────────────────┐
│ Your application (Python or C++) │
├──────────────────────────────────────────────────────────────┤
│ Python API layer (faiss/python/) │
│ __init__.py – Pythonic method replacements │
│ class_wrappers.py – numpy<->C++ argument adaptation │
│ extra_wrappers.py – Kmeans, ResultHeap, MapInt64ToInt64 │
│ gpu_wrappers.py – index_cpu_to_gpu, all-GPU helpers │
│ loader.py – runtime SIMD-level library selection │
│ swigfaiss*.swig – SWIG interface (generates bindings) │
├──────────────────────────────────────────────────────────────┤
│ C API (optional, c_api/) – flat C functions over the C++ API │
├──────────────────────────────────────────────────────────────┤
│ C++ core (faiss/) │
│ Index (abstract) ── IndexFlat, IndexIVF*, IndexPQ*, │
│ IndexHNSW, IndexNSG, IndexLSH, ... │
│ IndexBinary (abstract) ── IndexBinaryFlat, ...IVF, ...HNSW │
│ index_factory() – string → index pipeline builder │
│ index_io – write_index / read_index │
│ Clustering, VectorTransform, InvertedLists │
│ impl/ – algorithm internals (HNSW, PQ, ScalarQuantizer…) │
│ utils/ – distances, heaps, SIMD kernels, random │
│ gpu/ gpu_metal/ svs/ – accelerator & 3rd-party backends │
├──────────────────────────────────────────────────────────────┤
│ BLAS (MKL / OpenBLAS) + OpenMP [ + CUDA / ROCm / Metal ] │
└──────────────────────────────────────────────────────────────┘
The Index abstraction
The entire library hangs off faiss::Index (faiss/Index.h). It is an abstract struct with public data members and virtual methods:
Data members: int d (dimension), idx_t ntotal (count; idx_t = int64_t), bool is_trained, bool verbose, MetricType metric_type, float metric_arg.
Pure virtual (every index must implement): add(n, x), search(n, x, k, distances, labels, params), reset().
Virtual with defaults: train, train_with_queries, add_with_ids, range_search, assign, remove_ids, reconstruct, reconstruct_batch, reconstruct_n, search_and_reconstruct, compute_residual(_n), merge_from, check_compatible_for_merge, and the standalone codec interface (sa_code_size, sa_encode, sa_decode, add_sa_codes).
A newer numeric-type family (train_ex, add_ex, search_ex, add_with_ids_ex) accepts a NumericType (Float32, Float16, UInt8, Int8) so indexes can ingest non-float32 data where supported; the base implementations handle Float32 and throw on the rest.
Note
Search accepts an optional
SearchParameters*. Subclasses extend it (e.g.IVFSearchParameterswithnprobe,IndexRefineSearchParameterswithk_factor) so per-query parameters can be passed without mutating the index — important for thread-safe concurrent search with different settings.
Composition over inheritance
Many capabilities are added by wrapping rather than subclassing the algorithm:
IndexPreTransform— applies aVectorTransform(PCA, OPQ rotation, L2 normalization) before delegating to an inner index.IndexRefine/IndexRefineFlat— re-ranks an inner index's topk_factor · kcandidates with finer distances.IndexIDMap/IndexIDMap2— adds custom-ID support (and, for IDMap2, reconstruction by ID) to indexes that lack it.IndexIVF*— composes a coarse quantizer (itself anIndex, usuallyIndexFlatL2) with an encoding (Flat,PQ,ScalarQuantizer, additive quantizers, RaBitQ...).
The index_factory string grammar is exactly a serialization of these compositions: OPQ16_64,IVF1000,PQ16 means "OPQ pre-transform → IVF with 1000 cells → PQ16 encoding."
3. Repository Structure
faiss/ C++ core library (114 files at top level)
Index.h / Index.cpp abstract base + version macros (FAISS_VERSION 1.14.2)
MetricType.h MetricType enum, idx_t typedef
index_factory.{h,cpp} regex-based string → index builder
index_io.{h,cpp} serialization + IO flags + deser. hardening
IndexFlat, IndexIVF*, IndexPQ*, IndexHNSW, IndexNSG, IndexLSH,
IndexScalarQuantizer, IndexAdditiveQuantizer*, IndexRaBitQ*,
IndexRefine, IndexPreTransform, IndexIDMap, IndexBinary* ...
impl/ algorithm internals (HNSW, ProductQuantizer,
ScalarQuantizer, AdditiveQuantizer, fast_scan,
simdlib, AuxIndexStructures, IDSelector, ...)
utils/ distances, heaps, partitioning, random, SIMD,
hamming_distance, transpose, quantization kernels
invlists/ InvertedLists storage (RAM, on-disk, capped)
gpu/ CUDA/ROCm GPU indexes + StandardGpuResources
gpu_metal/ Apple Silicon Metal backend (IndexFlat)
svs/ Intel Scalable Vector Search integration (optional)
python/ SWIG bindings + Pythonic wrappers + loader
cppcontrib/ header-only helpers (sa_decode, etc.)
c_api/ optional flat C API (c_api/, c_api/gpu, impl, utils)
contrib/ Python helper modules (datasets, evaluation, ondisk,
torch_utils, clustering, ivf_tools, rpc, ...)
benchs/ benchmark scripts (bench_fw framework, IVF, HNSW, ...)
demos/ example programs (offline_ivf, rocksdb_ivf, ...)
perf_tests/ micro-benchmarks
tutorial/cpp, tutorial/python getting-started examples
tests/ C++ (GoogleTest) + Python test suites
conda/ conda recipes for faiss / faiss-gpu / faiss-gpu-cuvs
cmake/ CMake helpers + toolchains
CMakeLists.txt, INSTALL.md, Doxyfile, pyproject.toml, pyproject-gpu.toml
Note
The
benchs/,demos/, andperf_tests/scripts useargparseand look like CLI tools to automated scanners, but they are not a supported command-line interface — Faiss has no CLI. They are reproducibility harnesses for the research papers and performance regression checks.
4. System Requirements
Runtime (using a prebuilt package)
| Requirement | Detail |
|---|---|
| OS | Linux (x86-64, aarch64), macOS (arm64), Windows (x86-64) for faiss-cpu |
| BLAS | Bundled by the conda/pip package (MKL on x86-64, OpenBLAS on ARM) |
| Python | 3.x with NumPy (for the Python bindings) |
| GPU (optional) | NVIDIA CUDA 11.4/12.1 (faiss-gpu), CUDA 13.2 + cuVS 26.06 (faiss-gpu-cuvs) — Linux x86-64 only |
Build (from source)
| Requirement | Detail |
|---|---|
| Compiler | C++20 compiler with OpenMP ≥ 2 |
| BLAS | Any; Intel MKL strongly recommended on Intel for performance |
| CMake | Recent version |
| GPU (optional) | nvcc + CUDA toolkit (NVIDIA); AMD ROCm (AMD); libcuvs=26.06 (cuVS) |
| Python bindings (optional) | Python 3, NumPy, SWIG |
5. Building from Source
Faiss builds with CMake in the standard configure → build → install flow.
Step 1 — configure
cmake -B build .
Step 2 — build the C++ library
make -C build -j faiss
This produces libfaiss.a (or libfaiss.so with -DBUILD_SHARED_LIBS=ON).
Important
If you build with a non-generic SIMD level, build the corresponding optimized target before
swigfaiss, e.g.make -C build -j faiss_avx2(orfaiss_avx512,faiss_avx512_spr). The Python loader selects the matchingswigfaiss_*extension at import time (see Runtime SIMD Dispatch).
Step 3 — Python bindings (optional)
make -C build -j swigfaiss
(cd build/faiss/python && python setup.py install)
Step 4 — install C++ library & headers (optional)
make -C build install
Step 5 — test (optional)
# C++ (requires -DBUILD_TESTING=ON at configure time)
make -C build test
# Python
(cd build/faiss/python && python setup.py build)
PYTHONPATH="$(ls -d ./build/faiss/python/build/lib*/)" pytest tests/test_*.py
Tip
Pass
-jwithout a number to use all cores, but on memory-constrained machines pin it (-j4) — Faiss translation units, especially GPU and SIMD kernels, are memory-hungry to compile.
6. Build Configuration Reference
All options are passed to the cmake -B build . invocation as -D<OPTION>=<VALUE>.
General
| Option | Default | Effect |
|---|---|---|
FAISS_ENABLE_GPU |
ON |
Build GPU indices. |
FAISS_ENABLE_PYTHON |
ON |
Build the Python bindings. |
FAISS_ENABLE_C_API |
OFF |
Build the C API. |
BUILD_TESTING |
— | Build the C++ test suite. |
BUILD_SHARED_LIBS |
OFF |
Build a shared library (libfaiss.so) instead of static. |
Optimization
| Option | Values | Effect |
|---|---|---|
CMAKE_BUILD_TYPE |
Release, ... |
Release enables -O3-class optimization. |
FAISS_OPT_LEVEL |
x86: generic, avx2, avx512, avx512_spr; aarch64: generic, sve |
SIMD instruction set to compile for (increasing optimization). |
FAISS_USE_LTO |
ON/OFF (OFF) |
Link-Time Optimization. |
BLAS
| Option | Effect |
|---|---|
BLA_VENDOR=Intel10_64_dyn + MKL_LIBRARIES=/path/to/mkl/libs |
Use Intel MKL (significantly faster than OpenBLAS on Intel). |
GPU
| Option | Effect |
|---|---|
FAISS_ENABLE_CUVS=ON |
Use NVIDIA cuVS implementations for IVF-Flat, IVF-PQ, and CAGRA. Requires FAISS_ENABLE_GPU=ON. |
FAISS_ENABLE_ROCM=ON |
Build GPU indices for AMD GPUs. Requires FAISS_ENABLE_GPU=ON. |
CUDAToolkit_ROOT=/path/to/cuda |
Hint the CUDA toolkit location. |
CMAKE_CUDA_ARCHITECTURES="75;72" |
Target specific GPU architectures. |
Optional integrations
| Option | Effect |
|---|---|
FAISS_ENABLE_SVS=ON |
Enable Intel Scalable Vector Search (Vamana, LVQ, LeanVec). CMake fetches and builds libsvs_runtime.so, copied into the Python package; for C++ usage put it on your library path. |
FAISS_ENABLE_METAL |
Apple Silicon Metal backend (builds Metal tests when combined with BUILD_TESTING). |
Python
| Option | Effect |
|---|---|
Python_EXECUTABLE=/path/to/python |
Build bindings for a specific Python interpreter. |
7. Runtime SIMD Dispatch
A subtle but operationally important behavior: the Python package selects the best CPU-optimized extension at import time, based on the CPU it is running on. This is implemented in faiss/python/loader.py.
The loader determines the supported instruction sets (via NumPy's __cpu_features__, plus an SVE probe on aarch64 Linux), then tries to import the most-optimized matching extension first, falling back down the chain:
swigfaiss_avx512_spr → swigfaiss_avx512 → swigfaiss_avx2 → swigfaiss_sve → swigfaiss (generic)
Two environment variables control this:
| Variable | Effect |
|---|---|
FAISS_OPT_LEVEL |
If set (e.g. avx2, avx512, avx512_spr, sve), forces that level instead of auto-detecting. |
FAISS_DISABLE_CPU_FEATURES |
A whitespace/comma-separated list of features to remove from the detected set (e.g. disable AVX512 to work around a bad path or a CPU that throttles under AVX512). |
Warning
If no matching
swigfaiss*extension is present (common in incomplete from-source builds), import fails hard with a detailed message telling you whichFAISS_OPT_LEVELyour CPU supports and which target to build (swigfaiss,swigfaiss_avx2,swigfaiss_avx512,swigfaiss_avx512_spr, orswigfaiss_sve). This isNo module named 'faiss.swigfaiss'— almost always a build, not a usage, problem.
Note
v1.14.2 also adds dynamic dispatch (DD) for several kernel families (hamming, fast_scan) and a build mode where you select a subset of SIMD levels at dispatch time, plus RVV (RISC-V Vector) support with cross-compilation for riscv64.
8. The Index Class Hierarchy
index_factory.cpp includes every index type it can construct; that include list is the authoritative catalog of the C++ index families:
CPU float indexes
| Family | Classes | Notes |
|---|---|---|
| Exact | IndexFlat, IndexFlatL2, IndexFlatIP |
Brute force; supports the widest metric set. |
| Inverted file | IndexIVFFlat, IndexIVFFlatPanorama, IndexIVFPQ, IndexIVFPQR, IndexIVFPQFastScan, IndexIVFScalarQuantizer, IndexIVFSpectralHash, IndexIVFAdditiveQuantizer(FastScan), IndexIVFRaBitQ(FastScan) |
Coarse quantizer + per-cell encoding. nprobe at search. |
| Product quantization | IndexPQ, IndexPQFastScan |
Compact codes; FastScan uses SIMD LUTs. |
| Additive quantization | IndexAdditiveQuantizer, IndexAdditiveQuantizerFastScan |
Residual / Local Search quantizers. |
| Graph | IndexHNSW (Flat/PQ/SQ storage), IndexNSG |
High recall, no training, higher memory. |
| Compact / hashing | IndexLSH, IndexLattice, IndexRaBitQ, IndexScalarQuantizer, IndexRowwiseMinMax |
Various compression schemes. |
| Wrappers | IndexPreTransform, IndexRefine/IndexRefineFlat, Index2Layer, IndexIDMap/IndexIDMap2 |
Compose other indexes. |
Binary indexes (Hamming distance over bit vectors): IndexBinaryFlat, IndexBinaryIVF, IndexBinaryHNSW, IndexBinaryHash. Built via index_binary_factory.
Intel SVS (compile-time FAISS_ENABLE_SVS): IndexSVSFlat, IndexSVSIVF, IndexSVSIVFLVQ, IndexSVSIVFLeanVec, IndexSVSVamana, IndexSVSVamanaLVQ, IndexSVSVamanaLeanVec. As of v1.14.2 an SVS Vamana index can also serve as an IVF coarse quantizer via the factory.
Pre-processing transforms
VectorTransform subclasses applied through IndexPreTransform: PCA reduction, OPQ rotation (optimized for PQ), random rotation (RR), and L2 normalization (L2norm, the basis for cosine search).
9. Persistence & I/O
faiss/index_io.h defines the serialization API. Any index round-trips through a single file (or FILE*, or a custom IOReader/IOWriter abstraction).
void write_index(const Index* idx, const char* fname, int io_flags = 0);
Index* read_index(const char* fname, int io_flags = 0);
std::unique_ptr<Index> read_index_up(const char* fname, int io_flags = 0); // owning
Parallel functions exist for binary indexes (write_index_binary/read_index_binary), VectorTransform, ProductQuantizer, and InvertedLists.
I/O flags
| Flag | Value | Effect |
|---|---|---|
IO_FLAG_SKIP_STORAGE |
1 | Skip the raw storage for graph indexes (graph structure only). |
IO_FLAG_READ_ONLY |
2 | Open read-only; no in-place modification. |
IO_FLAG_ONDISK_SAME_DIR |
4 | Strip the directory from an on-disk inverted-list filename and assume it sits beside the index file. |
IO_FLAG_SKIP_IVF_DATA |
8 | Load list sizes only, not the IVF payload. |
IO_FLAG_SKIP_PRECOMPUTE_TABLE |
16 | Don't rebuild the precomputed table after load. |
IO_FLAG_PQ_SKIP_SDC_TABLE |
32 | Skip the PQ symmetric-distance table (blocks some distance computations; blocks HNSWPQ graph building). |
IO_FLAG_MMAP |
(composite) | Memory-map the data (loads ArrayInvertedLists as OnDiskInvertedLists). |
IO_FLAG_MMAP_IFC |
1<<9 |
Mmap codes for IndexFlatCodes-derived indexes and HNSW (also supported on Darwin as of v1.14.2). |
Tip
For indexes larger than RAM, the combination of on-disk inverted lists plus
IO_FLAG_MMAPlets the OS page index data in on demand. Thefaiss.contrib.ondiskhelpers and thedemos/offline_ivfexample show the full merge-to-on-disk workflow.
10. Security
Faiss has no network surface, no authentication, and no access control — it executes in your process. Its security profile is therefore about two inputs you control: index files you deserialize, and the vectors you process.
Untrusted index files are the primary risk
read_index deserializes a binary format that contains size and count fields (number of inverted lists, vector-transform chain length, hash counts, etc.). A malicious or corrupt file can specify enormous values to trigger pathological allocations or compute. Faiss v1.14.x ships explicit hardening knobs in index_io.h:
| Control | Default | Purpose |
|---|---|---|
set_deserialization_loop_limit(n) |
0 (no limit) | Reject loop-driving fields (nlist, nsplits, VT chain length, nhash, ...) that exceed n. |
set_deserialization_vector_byte_limit(n) |
1 TB (1<<40) |
Cap the bytes a single READVECTOR call may allocate. |
set_deserialization_lattice_r2_limit(n) |
0 (no limit) | Reject IndexLattice payloads whose squared radius r2 would build an unboundedly expensive decode cache. |
Caution
If your service loads index files supplied by users or fetched from untrusted storage, set these limits before any deserialization and run the load in an isolated process or sandbox. The functions are explicitly not thread-safe: configure them before any concurrent deserialization begins and do not change them mid-flight. There were also recent hardening commits validating HNSW and SVS deserialization read sites and adding format-enum sentinels.
Data-handling notes
- Faiss does not encrypt index files; stored vectors and PQ codes are recoverable. If your vectors are sensitive (e.g. derived from personal data), protect the files at rest and in transit at the storage layer.
- Reconstruction (
reconstruct,sa_decode) can return approximations of the original vectors from compressed indexes — relevant if you considered the codes "anonymized." - The library trusts caller-provided array shapes/dtypes; the Python layer validates dtype and contiguity and throws clear
TypeErrors, but C++ callers are responsible for correct sizes.
License & provenance
MIT-licensed, Copyright © Meta Platforms, Inc. Third-party components are listed in THIRD_PARTY_NOTICES. cuVS and SVS integrations pull in their own (Apache-2.0) licensed code.
11. GPU & Accelerator Backends
NVIDIA (CUDA / cuVS)
GPU support lives in faiss/gpu/. The entry object is StandardGpuResources, which manages per-device scratch memory and CUDA streams. Indexes move between host and device with index_cpu_to_gpu(res, device, index), index_cpu_to_all_gpus(index), and back with index_gpu_to_cpu(index). GPU indexes accept input from CPU or GPU memory; staying resident on the GPU avoids copy overhead.
When built with FAISS_ENABLE_CUVS=ON, IVF-Flat, IVF-PQ, and CAGRA can dispatch to NVIDIA cuVS implementations, and v1.14.2 adds filtered search for cuVS indexes and lets cuVS supply default values.
AMD (ROCm)
FAISS_ENABLE_ROCM=ON builds the GPU indices for AMD GPUs through HIP. The same gpu/ code path is compiled for HIP targets.
Apple Silicon (Metal)
faiss/gpu_metal/ adds a Metal backend for Apple Silicon. As of v1.14.2 it covers IndexFlat; the Metal shaders are extracted into standalone .metal files with a kernel wrapper class.
Note
GPU indexes do not implement every CPU index type or every operation. The drop-in story (
IndexFlatL2→GpuIndexFlatL2, orindex_cpu_to_gpu) holds for the common Flat/IVF/PQ paths; exotic CPU index types may have no GPU equivalent.
12. Operations & Scaling
Because Faiss is embedded, "operations" is about how your service uses it.
Threading
Faiss parallelizes batch add/search with OpenMP. Control thread count with the standard OMP_NUM_THREADS environment variable or faiss.omp_set_num_threads(n). Search throughput scales with batch size — submit queries in batches rather than one at a time.
Important
A single index is generally safe for concurrent search from multiple threads (search is
const), but concurrent add/train/removewith search is not. For IVF, prefer passing per-querySearchParametersover mutatingindex.nprobefrom multiple threads. HNSW gained optional persistent locks in v1.14.2 for safe incremental adds.
Indexes larger than RAM
Three complementary strategies:
- Compression —
IndexIVFPQand additive-quantizer indexes shrink each vector to a few bytes, letting billions fit in RAM. - On-disk inverted lists — build per-shard indexes and merge to a single on-disk index (
faiss.contrib.ondisk,demos/offline_ivf), then load withIO_FLAG_MMAP. - Sharding / distributed — split the database across machines and query in parallel (
contrib/rpc.py,contrib/client_server.py,benchs/distributed_ondisk).
Reproducibility & monitoring
Seed RNGs (np.random.seed, Kmeans(seed=...)). Faiss has no built-in metrics export; instrument query latency and recall in your service. Validate recall against an IndexFlatL2 ground truth in CI when you change index parameters.
13. Performance Tuning
| Lever | Index family | Effect |
|---|---|---|
nprobe |
IVF | More cells scanned → higher recall, lower QPS. The primary recall/speed dial. |
nlist |
IVF (build) | More cells → finer partitioning; rule of thumb ~sqrt(N) to 16*sqrt(N). Larger nlist needs more training data. |
efSearch |
HNSW | Higher → higher recall, slower search. |
efConstruction, M |
HNSW (build) | Higher → better graph quality, slower build, more memory. |
m, nbits |
PQ | More sub-quantizers / bits → better accuracy, more memory and compute. |
Refine(...) + k_factor |
any compressed | Re-rank more candidates with exact distances → recover recall at modest cost. |
| OPQ pre-transform | PQ-based | Rotates space so PQ quantizes better → higher accuracy for free at query time. |
FAISS_OPT_LEVEL / SIMD build |
all CPU | AVX512/AVX512-SPR/SVE kernels are substantially faster than generic. |
| Intel MKL BLAS | flat / exact | MKL is markedly faster than OpenBLAS on Intel for the BLAS-bound exact path. |
Tip
The
benchs/bench_fwframework anddemos/demo_auto_tune.pyautomate the recall-vs-speed sweep across index types and parameters, producing Pareto fronts. Use them to pick an operating point rather than guessing.
Note
v1.14.2 adds throughput-oriented features worth knowing: database-parallel flat search for few-query workloads, IVF early-termination, a Kmeans early-stop threshold, TurboQuant (CPU), Panorama optimizations, and
SuperKMeans(ADSampling + PDX pruning) for faster clustering.
14. The C API
c_api/ provides a flat C interface over the C++ library, enabled with -DFAISS_ENABLE_C_API=ON. It mirrors the C++ surface — index construction, faiss_Index_train/add/search, index_factory, write_index/read_index — using opaque handles and integer error codes instead of exceptions. Subdirectories: c_api/impl (error handling), c_api/utils, and c_api/gpu (GPU bindings). This is the integration point for languages other than C++/Python (Rust, Go, Java, etc. binders build on it).
Note
The C API is opt-in and not built by the default conda/pip packages. Build it from source if you need it.
15. Code Quality & Conventions
- Language standard: C++17/20. Header + implementation split (
IndexX.h/IndexX.cpp); algorithm internals isolated underimpl/, reusable numeric kernels underutils/. - Error handling: C++ uses
FAISS_THROW_MSG/FAISS_THROW_FMT/FAISS_THROW_IF_NOT_FMT(seeimpl/FaissAssert.h) to raiseFaissException. Recent work replacedFAISS_ASSERTwith throwing variants for recoverable conditions (e.g. unsupported SVS storage kinds) and added OpenMP exception-capture helpers so exceptions thrown inside parallel regions propagate correctly. - Matrix convention: all vector batches are compact, row-major
n × darrays offloat32; elementjof vectoriisx[i*d + j]. - SIMD strategy: a
simdlibabstraction plus per-level translation units, increasingly via dynamic dispatch so one binary can pick kernels at runtime. Cross-SIMD-level correctness is enforced with bit-exact reference tests (@for_all_simd_levels,NoneSIMDLevelcontext manager). - Python ergonomics: SWIG generates raw bindings;
faiss/python/*.pythen replaces methods so they accept NumPy arrays and return(D, I)tuples instead of requiring explicit pointers and counts.class_wrappers.pyvalidates dtype/contiguity and raises clearTypeErrors.
16. Testing
- C++: GoogleTest, fetched via CMake
FetchContent(release-1.12.1). The suite (tests/CMakeLists.txt) covers IVF, PQ encoding/codec, HNSW, NSG, scalar quantizer, merge/on-disk/mmap (POSIX-only), heaps, partitioning, fast-scan, SIMD levels, callbacks, and zero-copy paths. x86 AVX2/AVX512 intrinsic tests compile only underFAISS_OPT_LEVEL=ddon x86-64; SVS tests gate onFAISS_ENABLE_SVS. Windows defers gtest discovery to ctest time (the DLL isn't onPATHat build time) and skips POSIX-API tests. - Python:
pytest tests/test_*.pyagainst the built extension; GPU tests underfaiss/gpu/test/, Metal tests underfaiss/gpu_metal/test/. - Backward compatibility:
tests/index_io_backward_compatibility/verifies that indexes written by older versions still load — important given the serialization format is a public contract.
Important
When changing any serialization code, run the backward-compatibility tests and add a fixture for the new format. Index files in the wild outlive the code that wrote them.
17. Potential Improvements & Known Issues
Drawn from the live issue tracker at the documented commit:
| Issue | Status | Impact |
|---|---|---|
Data race in NNDescent::update() — unlocked read of other.pool.back() before acquiring the lock (#5276) |
Open bug | Potential corruption/crash during concurrent NNDescent graph construction. |
fast_scan fails to compile on AMD Zen5 with any FAISS_OPT_LEVEL (#5245) |
Open bug | Blocks from-source builds on Zen5; use prebuilt packages or a different opt level. |
Missing musllinux wheels on 1.14.2 (#5272) |
Open | Alpine/musl users cannot pip install; use conda or build from source. |
| New Python type stubs not included in the conda package (#5261) | Open | Editor type-checking is degraded under conda installs. |
Index.reconstruct_n() stub resolves to torch.Tensor under mypy for default CPU calls returning numpy.ndarray (#5232) |
Open | Type-checker false signal; runtime behavior is correct. |
SWIG 4.4 DeprecationWarning: builtin type has no __module__ attribute (#4481) |
Open feature/upgrade | Forward-compat with newer SWIG. |
Import failure on Python 3.12 via deprecated numpy.distutils (#3936) |
Resolved | Fixed by NumPy ≥ 2.0 __cpu_features__ path in loader.py. |
| Windows ARM64 (MSVC) build broken by NEON SIMD templatization (#4993) | Resolved | — |
Architectural opportunities (observed from the source):
- The serialization hardening limits (Security) default to permissive (
0/1 TB). Services accepting untrusted index files should consider whether Faiss should ship safer defaults or a documented "untrusted load" preset. - SIMD dispatch is mid-migration from static per-level TUs to dynamic dispatch; consolidating fully would simplify the build matrix and the loader fallback chain.
- GPU coverage is uneven across index types; a capability matrix in the docs (which
IndexXhas a GPU/Metal/cuVS equivalent) would reduce surprises.
18. Quick Reference
Build cheat sheet
# CPU, AVX2, shared lib, with Python and C API
cmake -B build . -DCMAKE_BUILD_TYPE=Release -DFAISS_OPT_LEVEL=avx2 \
-DBUILD_SHARED_LIBS=ON -DFAISS_ENABLE_GPU=OFF \
-DFAISS_ENABLE_PYTHON=ON -DFAISS_ENABLE_C_API=ON
make -C build -j faiss_avx2 swigfaiss
(cd build/faiss/python && python setup.py install)
# NVIDIA GPU with cuVS
cmake -B build . -DFAISS_ENABLE_GPU=ON -DFAISS_ENABLE_CUVS=ON \
-DCMAKE_CUDA_ARCHITECTURES="80;90"
make -C build -j faiss swigfaiss
Key environment variables
| Variable | Scope | Effect |
|---|---|---|
FAISS_OPT_LEVEL |
runtime + build | Force SIMD level. |
FAISS_DISABLE_CPU_FEATURES |
runtime | Disable specific CPU features at load. |
OMP_NUM_THREADS |
runtime | OpenMP thread count for add/search. |
Deserialization hardening (untrusted index files)
faiss.set_deserialization_loop_limit(10_000_000) # cap nlist/nhash/etc.
faiss.set_deserialization_vector_byte_limit(1 << 32) # cap single-vector alloc to 4 GB
faiss.set_deserialization_lattice_r2_limit(1 << 16) # cap IndexLattice r2
index = faiss.read_index("untrusted.faiss", faiss.IO_FLAG_READ_ONLY)
Deployment checklist
- [ ] Install a prebuilt package (conda/pip) unless you need a custom build.
- [ ] Confirm the SIMD level matches the deployment CPU (or rely on auto-dispatch).
- [ ] Pin
OMP_NUM_THREADSto your CPU allocation in containerized deployments. - [ ] Validate recall against an
IndexFlatL2ground truth before shipping parameter changes. - [ ] If loading untrusted index files, set deserialization limits and sandbox the load.
- [ ] Run backward-compatibility tests after any serialization change.
- [ ] For >RAM datasets, choose compression, on-disk+mmap, or sharding deliberately.
Version & provenance
| Fact | Value |
|---|---|
| Version | 1.14.2 |
| License | MIT (© Meta Platforms, Inc.) |
| Language | C++17/20 + SWIG Python bindings + optional C API |
| Hard dependency | BLAS (MKL / OpenBLAS) |
| Documented commit | eb4c1ea |