All notable changes to SimpleVecDB will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[2.2.0] - 2026-01-17
Added
- Vector Clustering & Auto-Tagging - Discover natural groupings in embeddings
VectorCollection.cluster()- Cluster documents by semantic similarity- K-means: Classic centroid-based clustering for balanced clusters
- MiniBatch K-means: Scalable variant for large datasets (default)
- HDBSCAN: Density-based clustering that auto-discovers cluster count
VectorCollection.auto_tag()- Generate descriptive tags for clusters- TF-IDF method (default): Extract keywords with highest TF-IDF scores
- Frequency method: Extract most common words per cluster
- Custom callback: Implement custom tagging logic (e.g., LLM-based)
VectorCollection.assign_cluster_metadata()- Persist cluster IDs to document metadata-
VectorCollection.get_cluster_members()- Retrieve all documents in a cluster -
Cluster Quality Metrics - Evaluate clustering results
ClusterResult.inertia- Sum of squared distances to centroids (K-means only, lower is better)ClusterResult.silhouette_score- Cluster separation metric (-1 to 1, higher is better)-
ClusterResult.metrics()- Get all metrics as dictionary -
Cluster Persistence - Save and reuse cluster configurations
VectorCollection.save_cluster()- Save cluster centroids and metadata to databaseVectorCollection.load_cluster()- Load saved cluster configurationVectorCollection.list_clusters()- List all saved cluster configurationsVectorCollection.delete_cluster()- Delete a saved cluster configuration-
VectorCollection.assign_to_cluster()- Assign new documents to saved clusters without re-clustering -
Async Clustering Support - Full async/await parity for all clustering operations
AsyncVectorCollection.cluster(),auto_tag(),assign_cluster_metadata(),get_cluster_members()-
AsyncVectorCollection.save_cluster(),load_cluster(),list_clusters(),delete_cluster(),assign_to_cluster() -
New Dependencies - Now included in standard installation
scikit-learn>=1.3.0- K-means, MiniBatch K-means, silhouette scorehdbscan>=0.8.33- Density-based clusteringsqlcipher3-binary>=0.5.0- Encryption support (previously optional)-
cryptography>=41.0- Encryption utilities (previously optional) -
Documentation
- New comprehensive clustering guide:
docs/guides/clustering.md- Algorithm comparison and selection guide
- Quality metrics interpretation
- Cluster persistence workflows
- Use cases: product categorization, topic discovery, customer segmentation, duplicate detection
- Best practices and troubleshooting
- New types reference:
docs/api/types.md- Complete
ClusterResultAPI documentation Document,DistanceStrategy,Quantization,ClusterAlgorithmreference
- Complete
- Updated README.md and docs/index.md with clustering sections
- Enhanced
docs/api/core.mdwith clustering examples
Changed
- pyproject.toml: Updated
scikit-learnminimum version from1.0to1.3.0for improved clustering stability
Testing
- Added 26 clustering tests in
tests/unit/test_clustering.py: - 16 core clustering tests (algorithms, auto-tagging, metadata persistence, edge cases)
- 4 cluster metrics tests (inertia, silhouette, metrics method)
- 6 cluster persistence tests (save/load/list/delete/assign)
- Added 3 async clustering tests in
tests/unit/test_async.py - Total test count: 305 (up from 292)
Installation
Clustering and encryption are now included by default:
pip install simplevecdb
No extra installation steps required!
Example
from simplevecdb import VectorDB
db = VectorDB("products.db")
collection = db.collection("items")
# Cluster documents
result = collection.cluster(n_clusters=5, algorithm="minibatch_kmeans")
# Generate tags and persist
tags = collection.auto_tag(result, method="tfidf", n_keywords=3)
collection.assign_cluster_metadata(result, tags)
# Save for fast assignment of new documents
collection.save_cluster("categories", result, metadata={"tags": tags})
# Later: assign new documents without re-clustering
new_ids = collection.add_texts(new_texts, embeddings=new_embeddings)
collection.assign_to_cluster("categories", new_ids)
# Evaluate quality
print(f"Silhouette Score: {result.silhouette_score:.2f}") # 0.62
print(f"Inertia: {result.inertia:.2f}") # 1523.45
[2.0.0] - 2025-12-23
Breaking Changes
- Backend Migration: sqlite-vec → usearch HNSW
- Vector search now uses usearch's high-performance HNSW algorithm
- 10-100x faster similarity search for large collections
- Vector data stored in separate
.usearchfiles per collection (e.g.,mydb.db.default.usearch) -
SQLite still stores metadata, text, and FTS5 index
-
Removed
DistanceStrategy.L1- Manhattan distance not supported by usearch -
Storage Format Change
- Embeddings now stored in both usearch index AND SQLite (for MMR support)
- Existing sqlite-vec databases will auto-migrate on first open
- Migration is one-way; backup before upgrading
Added
usearch_index.py- New UsearchIndex wrapper class:- Thread-safe HNSW index operations (lock on writes, lock-free reads)
- Automatic persistence to
.usearchfiles - Upsert support (removes existing keys before add)
- BIT quantization using Hamming metric with bit packing
-
Configurable HNSW parameters (connectivity, expansion_add, expansion_search)
-
Proper MMR Implementation - Max Marginal Relevance now computes actual pairwise similarity between candidates and selected documents using stored embeddings
-
Embedding Storage in SQLite - Embeddings stored as BLOB for:
- Accurate MMR diversity computation
- Future index rebuild from SQLite backup
-
Schema auto-migrates existing tables
-
VectorCollection.rebuild_index()- Reconstruct usearch HNSW index from SQLite embeddings: - Useful for index corruption recovery
- Tune HNSW parameters (connectivity, expansion_add, expansion_search)
-
Reclaim space after many deletions
-
VectorDB.check_migration(path)- Dry-run migration check: - Reports which collections need migration
- Shows total vector count and estimated storage
-
Provides detailed rollback instructions
-
Adaptive Search - Automatically optimizes search strategy based on collection size:
- Collections < 10k vectors use brute-force (
exact=True) for perfect recall - Collections ≥ 10k vectors use HNSW for faster approximate search
-
Threshold configurable via
constants.USEARCH_BRUTEFORCE_THRESHOLD -
exactparameter - Force search mode insimilarity_search(): None(default): adaptive based on collection sizeTrue: force brute-force for perfect recall-
False: force HNSW approximate search -
Quantization.FLOAT16- Half-precision floating point: - 2x memory savings compared to FLOAT32
- 1.5x faster search with minimal precision loss
-
Ideal for embeddings where full precision isn't needed
-
threadsparameter - Parallel execution control: - Added to
add_texts()andsimilarity_search() 0(default): auto-detect optimal thread count-
Explicit value: control parallelism for batch operations
-
Auto Memory-Mapping - Large indexes automatically use memory-mapped mode:
- Indexes >100k vectors use
view=Truefor instant startup - Lower memory footprint for large collections
- Transparent upgrade to writable mode on add operations
-
Configurable via
constants.USEARCH_MMAP_THRESHOLD -
similarity_search_batch()- Multi-query batch search: - ~10x throughput for batch query workloads
- Uses usearch's native batch search under the hood
-
Same parameters as
similarity_search()but accepts list of queries -
examples/backend_benchmark.py- Benchmark script comparing usearch vs brute-force: - Measures speedup, recall, and storage efficiency
- Supports all quantization levels
- Validates 10-100x performance claims
Changed
- Dependencies: Replaced
sqlite-vec>=0.1.6withusearch>=2.12 - CatalogManager: Removed vec0 virtual table operations, added embedding column
- SearchEngine: Rewrote to use UsearchIndex for all vector operations
- VectorCollection: Creates usearch index at
{db_path}.{collection}.usearch
Migration Notes
- Backup your database before upgrading
- On first open, existing sqlite-vec data will be migrated automatically
- New
.usearchfiles will be created alongside your.dbfile - The legacy sqlite-vec table is dropped after successful migration
1.3.0 - 2025-12-07
Added
- Structured Logging Module - New
simplevecdb.loggingmodule for production-grade observability get_logger(name)- Get namespaced loggers undersimplevecdb.*configure_logging(level, format, handler)- One-call logging setuplog_operation(name, **context)- Context manager for operation timing and error tracking-
log_error(operation, error, **context)- Consistent error logging with context -
SQLite Lock Retry Logic - Automatic retry with exponential backoff for database lock contention
@retry_on_lock(max_retries, base_delay, max_delay, jitter)decoratorDatabaseLockedErrorexception for exhausted retries with attempt/wait metrics-
Applied to
add_texts()anddelete_by_ids()operations in CatalogManager -
Filter Validation - Early validation of metadata filter dictionaries
validate_filter(filter_dict)- Validates keys are strings, values are supported types- Clear error messages for invalid filter structures
-
Automatically called in
build_filter_clause()before SQL generation -
New Exports - Added to
simplevecdb.__all__: get_logger,configure_logging,log_operationDatabaseLockedError,retry_on_lock,validate_filter
Changed
- CatalogManager internal refactoring:
add_texts()now delegates to_insert_batch()which has retry logicdelete_by_ids()now has retry logic for lock contentionbuild_filter_clause()validates filters before processingdelete_by_ids()no longer auto-vacuums - CallVectorDB.vacuum()separately to reclaim disk space after large deletions. This improves performance for batch deletions.- RateLimiter now includes TTL-based cleanup to prevent memory exhaustion on long-running servers with many unique clients (default: 1 hour TTL, 10k max buckets).
- AsyncVectorDB.close() now guarantees database connection is closed even if executor shutdown fails.
Testing
- Added 25 new tests in
tests/unit/test_error_handling.py: - 7 tests for
retry_on_lockdecorator behavior - 2 tests for
DatabaseLockedErrorexception - 4 tests for
validate_filterfunction - 8 tests for logging utilities
- 4 integration tests for error handling in VectorDB operations
Example
import logging
from simplevecdb import (
VectorDB,
configure_logging,
get_logger,
log_operation,
DatabaseLockedError,
)
# Enable debug logging
configure_logging(level=logging.DEBUG)
logger = get_logger(__name__)
try:
with log_operation("bulk_insert", collection="docs", count=1000):
db = VectorDB("data.db")
collection = db.collection("docs")
collection.add_texts(texts, embeddings=embeddings)
except DatabaseLockedError as e:
logger.error(f"Insert failed after {e.attempts} attempts")
1.2.0 - 2025-11-25
Added
- Async API Support - New
AsyncVectorDBandAsyncVectorCollectionclasses - Full async/await support for all collection operations
- Uses ThreadPoolExecutor to avoid blocking event loops
- Async context manager support (
async with AsyncVectorDB(...)) - All methods mirror sync API:
add_texts,similarity_search,keyword_search,hybrid_search,max_marginal_relevance_search,delete_by_ids,remove_texts - Configurable thread pool size via
max_workersparameter
Changed
- Added
pytest-asyncioto dev dependencies for async test support
Example
import asyncio
from simplevecdb import AsyncVectorDB
async def main():
async with AsyncVectorDB("data.db") as db:
collection = db.collection("docs")
await collection.add_texts(["Hello"], embeddings=[[0.1]*384])
results = await collection.similarity_search([0.1]*384, k=5)
return results
asyncio.run(main())
1.1.1 - 2025-11-23
Changed
- Refactored configuration constants into dedicated
constants.pymodule - Extracted hardware batch size thresholds (VRAM, CPU cores, ARM variants)
- Extracted search defaults (k=5, rrf_k=60, fetch_k=20)
- Improved maintainability and centralized configuration
Fixed
- Updated dependencies
- Bumped
sentence-transformers[onnx]from 3.3.1 to 5.1.2 - All embeddings/server tests passing with new version
1.1.0 - 2025-11-23
🏗️ Architecture Refactoring
Major internal restructuring for better maintainability and extensibility while preserving backward compatibility.
Changed
- Refactored core.py (879→216 lines, 75% reduction)
- Extracted search operations to
engine/search.py(SearchEngine) - Extracted quantization logic to
engine/quantization.py(QuantizationStrategy) - Extracted catalog management to
engine/catalog.py(CatalogManager) - Core now uses clean facade pattern with delegation
- Improved documentation
- Added comprehensive Google-style docstrings to all public API methods
- Reorganized MkDocs navigation with dedicated Engine section
- Updated architecture documentation in AGENTS.md and CONTRIBUTING.md
- Simplified CODE_OF_CONDUCT.md to be more approachable
Added
- Security infrastructure
- GitHub Actions workflow for weekly security scans (Bandit, Safety, Semgrep)
- Dependabot configuration for automated dependency updates
- Bandit configuration with validated false-positive suppressions
- Automated publishing
- GitHub Actions workflow for PyPI publishing on releases
- Test coverage improvements
- Added 11 new tests covering edge cases in search engine
- Maintained 97% overall coverage across refactored modules
Fixed
- Fixed unused
filter_builderparameter in_brute_force_searchmethod - Simplified brute-force filtering to use proper filter builder delegation
- Fixed import paths for embeddings module in search engine
Internal
- All modules now follow consistent interface patterns
- Engine components properly isolated with clear responsibilities
- No breaking changes to public API
1.0.0 - 2025-11-23
🎉 Initial Release
SimpleVecDB's first stable release brings production-ready local vector search to a single SQLite file.
Added
Core Features
- Multi-collection catalog system: Organize documents in named collections within a single database
- Vector search: Cosine, L2 (Euclidean), and L1 (Manhattan) distance metrics
- Quantization: FLOAT32, INT8 (4x compression), and BIT (32x compression) support
- Metadata filtering: JSON-based filtering with SQL
WHEREclauses - Batch processing: Automatic batching for efficient bulk operations
- Persistence: Single
.dbfile with WAL mode for concurrent reads
Hybrid Search
- BM25 keyword search: Full-text search using SQLite FTS5
- Hybrid search: Reciprocal Rank Fusion combining BM25 + vector similarity
- Query vector reuse: Pass pre-computed embeddings to avoid redundant embedding calls
- Metadata filtering: Works across all search modes (vector, keyword, hybrid)
Embeddings Server
- OpenAI-compatible API:
/v1/embeddingsendpoint for local embedding generation - Model registry: Configure allowed models or allow arbitrary HuggingFace repos
- Request limits: Configurable max batch size per request
- API key authentication: Optional Bearer token / X-API-Key authentication
- Usage tracking: Per-key request and token metrics via
/v1/usage - Model listing:
/v1/modelsendpoint for registry inspection - ONNX optimization: Quantized ONNX runtime for fast CPU inference
Hardware Optimization
- Auto-detection: Automatically detects CUDA GPUs, Apple Silicon (MPS), ROCm, and CPU
- Adaptive batching: Optimal batch sizes based on:
- NVIDIA GPUs: 64-512 (scaled by VRAM 4GB-24GB+)
- AMD GPUs: 256 (ROCm)
- Apple Silicon: 32-128 (M1/M2 vs M3/M4, base vs Max/Ultra)
- ARM CPUs: 4-16 (mobile, Raspberry Pi, servers)
- x86 CPUs: 8-64 (scaled by core count)
- Manual override:
EMBEDDING_BATCH_SIZEenvironment variable
Integrations
- LangChain:
SimpleVecDBVectorStorewith async support and MMR similarity_search,similarity_search_with_scoremax_marginal_relevance_searchkeyword_search,hybrid_searchadd_texts,add_documents,delete- LlamaIndex:
SimpleVecDBLlamaStorewith query mode support VectorStoreQueryMode.DEFAULT(dense vector)VectorStoreQueryMode.SPARSE/TEXT_SEARCH(BM25)VectorStoreQueryMode.HYBRID/SEMANTIC_HYBRID(fusion)- Metadata filtering across all modes
Examples & Documentation
- RAG notebooks: LangChain, LlamaIndex, and Ollama integration examples
- Performance benchmarks: Insertion speed, query latency, storage efficiency
- API documentation: Full class and method reference via MkDocs
- Setup guide: Environment variables and configuration options
- Contributing guide: Development setup and testing instructions
Configuration
EMBEDDING_MODEL: HuggingFace model ID (default:Snowflake/snowflake-arctic-embed-xs)EMBEDDING_CACHE_DIR: Model cache directory (default:~/.cache/simplevecdb)EMBEDDING_MODEL_REGISTRY: Comma-separatedalias=repo_identriesEMBEDDING_MODEL_REGISTRY_LOCKED: Enforce registry allowlist (default:1)EMBEDDING_BATCH_SIZE: Inference batch size (auto-detected if not set)EMBEDDING_SERVER_MAX_REQUEST_ITEMS: Max prompts per/v1/embeddingscallEMBEDDING_SERVER_API_KEYS: Comma-separated API keys for authenticationDATABASE_PATH: SQLite database path (default::memory:)SERVER_HOST: Embeddings server host (default:0.0.0.0)SERVER_PORT: Embeddings server port (default:8000)
Performance
Benchmarks on i9-13900K & RTX 4090 with 10k vectors (384-dim):
| Quantization | Storage | Insert Speed | Query Time (k=10) |
|---|---|---|---|
| FLOAT32 | 15.50 MB | 15,585 vec/s | 3.55 ms |
| INT8 | 4.23 MB | 27,893 vec/s | 3.93 ms |
| BIT | 0.95 MB | 32,321 vec/s | 0.27 ms |
Testing
- 177 unit and integration tests
- 97% code coverage
- Type-safe (mypy strict mode)
- CI/CD on Python 3.10, 3.11, 3.12, 3.13
Dependencies
- Core:
sqlite-vec>=0.1.6,numpy>=2.0,python-dotenv>=1.2.1,psutil>=5.9.0 - Server extras:
fastapi>=0.115,uvicorn[standard]>=0.30,sentence-transformers[onnx]==3.3.1
Notes
- Requires SQLite builds with FTS5 enabled for keyword/hybrid search (bundled with Python 3.10+)
- Works on Linux, macOS, Windows, and WASM environments
- Zero external dependencies beyond Python for core functionality
Links
- GitHub: https://github.com/coderdayton/simplevecdb
- PyPI: https://pypi.org/project/simplevecdb/
- Documentation: https://coderdayton.github.io/simplevecdb/
- License: MIT