How to Swap Vector Store Backends in Semantica Without Code Changes
You can swap vector store backends in Semantica by changing the backend string and config dictionary passed to the VectorStore façade class, eliminating the need to modify import statements, method signatures, or business logic.
Semantica’s vector store architecture is built around a configuration-driven façade pattern that abstracts concrete backend implementations behind a unified interface. This design allows you to migrate from local in-memory storage to production-grade vector databases like PostgreSQL pgvector or Pinecone simply by updating initialization parameters.
How the VectorStore Façade Enables Backend Swapping
At the core of this capability is the VectorStore class located in /semantica/vector_store/vector_store.py. This class acts as a façade that reads a backend name and a configuration dictionary at construction time, then lazily instantiates the appropriate concrete store through the internal _init_backend_store method.
When you call VectorStore(backend="faiss", config={"dimension": 384}), the façade does not immediately import FAISS. Instead, it stores your configuration and postpones backend initialization until the first operation. This lazy loading mechanism ensures that heavy dependencies are only imported when actually needed, and that the same code path works regardless of which backend you select.
The façade handles all method dispatch—including store_vectors, search_vectors, and delete operations—by routing calls to the underlying concrete implementation. Because every backend exposes an identical public API, your application code remains agnostic to whether vectors are stored in SQLite, Qdrant, or Milvus.
Supported Vector Store Backends
Semantica supports eight distinct vector store backends, each optimized for different deployment scenarios:
- faiss – Local Facebook AI Similarity Search for development and single-node deployments
- pgvector – PostgreSQL extension for production-grade persistent storage
- qdrant – High-performance vector search engine with standalone or cloud deployment
- milvus – Distributed vector database designed for enterprise scale
- pinecone – Fully managed vector database service requiring API credentials
- sqlite – File-based storage using sqlite-vec for lightweight applications
- inmemory – Ephemeral RAM-based storage for testing and prototyping
- weaviate – Vector search engine with semantic capabilities
The SUPPORTED_BACKENDS constant in the source code validates your selection at runtime, raising a clear error if you specify an unsupported backend name.
Step-by-Step: Swapping Backends via Configuration
Follow these three steps to switch vector store technologies without touching your application logic:
-
Select the backend identifier. Choose one of the supported strings (e.g.,
"pgvector","qdrant","faiss"). This value becomes thebackendparameter in yourVectorStoreconstructor. -
Provide backend-specific configuration. Pass a dictionary containing connection parameters via the
configargument. For PostgreSQL pgvector, this includes"connection_string"and"table_name"; for SQLite, specify"db_path"; for Pinecone, provide"api_key"and"environment". The_init_backend_storemethod unpacks these values when initializing the concrete store. -
Initialize the store. Create the instance with
store = VectorStore(backend="your_choice", config={...}). The façade automatically imports the required module (e.g.,pgvector_store) and instantiates it. If dependencies are missing, Semantica raises an informativeImportErrordirecting you to install the appropriate package.
Code Examples: From FAISS to PostgreSQL Without Code Changes
The following examples demonstrate how identical application code works across different backends by only changing initialization parameters.
Local FAISS for Development
from semantica.vector_store import VectorStore
# Initialize local FAISS store
faiss_store = VectorStore(
backend="faiss",
config={"dimension": 384}
)
# Store and search vectors
faiss_store.store_vectors(
vectors=[[0.1, 0.2, 0.3]],
metadata=[{"type": "demo"}]
)
results = faiss_store.search_vectors(
query_vector=[0.1, 0.2, 0.3],
k=5
)
PostgreSQL pgvector for Production
Notice that the storage and retrieval method calls remain identical; only the initialization changes.
from semantica.vector_store import VectorStore
# Switch to remote PostgreSQL with pgvector extension
pg_store = VectorStore(
backend="pgvector",
config={
"connection_string": "postgresql://user:password@db.example.com/semantica",
"table_name": "vector_entries",
"dimension": 384,
"distance_metric": "cosine",
},
)
# Identical API calls - zero code changes required
pg_store.store_vectors(
vectors=[[0.1, 0.2, 0.3]],
metadata=[{"type": "demo"}]
)
results = pg_store.search_vectors(
query_vector=[0.1, 0.2, 0.3],
k=5
)
Dynamic Backend Selection via Environment Variables
For CI/CD pipelines and containerized deployments, externalize the backend choice to environment variables:
import os
from semantica.vector_store import VectorStore
# Configure via environment
backend = os.getenv("SEMANTICA_VECTOR_BACKEND", "sqlite")
config = {}
if backend == "sqlite":
config["db_path"] = os.getenv("VECTOR_DB_PATH", "vectors.db")
elif backend == "pinecone":
config["api_key"] = os.getenv("PINECONE_API_KEY")
config["environment"] = os.getenv("PINECONE_ENV")
# Single initialization point handles all backends
store = VectorStore(backend=backend, config=config)
# Application logic remains constant regardless of backend
store.store_vectors([[0.1, 0.2, 0.3]], metadata=[{"source": "api"}])
Handling Missing Dependencies Gracefully
When you specify a backend whose dependencies are not installed, the _init_backend_store method in /semantica/vector_store/vector_store.py catches the import failure and raises a descriptive ImportError. For example, selecting backend="pgvector" without installing psycopg2 or pgvector will prompt you to install the required package. This prevents your application from crashing with obscure module errors and allows you to keep optional dependencies out of your base installation until needed.
Summary
- Configuration-driven architecture: The
VectorStorefaçade in/semantica/vector_store/vector_store.pyabstracts all backend implementations behind a unified interface controlled by thebackendparameter andconfigdictionary. - Zero code changes: You can migrate from FAISS to pgvector, Qdrant, or Pinecone by only modifying initialization arguments, leaving all
store_vectors()andsearch_vectors()calls untouched. - Lazy initialization: Backends are instantiated only when first used via
_init_backend_store, ensuring efficient resource usage and clear error messages for missing dependencies. - Eight supported backends: Choose from
faiss,pgvector,qdrant,milvus,pinecone,sqlite,inmemory, orweaviatebased on your scaling and persistence requirements.
Frequently Asked Questions
What happens if I specify a backend that is not installed?
Semantica raises an ImportError with instructions to install the missing package. The error occurs inside _init_backend_store when the façade attempts to import the concrete store module (e.g., pgvector_store), allowing you to install optional dependencies only for the backends you actually use.
Can I swap backends at runtime without restarting my application?
Yes. Since VectorStore is initialized with a specific backend string, you can create multiple instances with different backends simultaneously or reinitialize the store with new parameters. However, data stored in one backend does not automatically migrate to another—you must handle vector migration separately.
Does the public API differ between backends?
No. All backends implement identical methods including store_vectors(), search_vectors(), and delete operations. The façade ensures that backend-specific quirks (such as connection pooling in pgvector or index types in FAISS) are handled internally through the configuration dictionary, exposing a consistent interface to your application code.
Which backend should I use for production versus development?
For development and testing, use inmemory or sqlite for zero-config setup, or faiss for local high-performance search. For production, use pgvector if you already run PostgreSQL, pinecone for fully-managed serverless vector search, or qdrant/milvus for self-hosted high-throughput scenarios requiring horizontal scaling.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →