# How to Swap Vector Store Backends in Semantica Without Code Changes

> Effortlessly swap Semantica vector store backends without code changes. Simply update the backend string and config in the VectorStore façade for seamless integration.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: how-to-guide
- Published: 2026-09-13

---

**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`](https://github.com/semantica-agi/semantica/blob/main//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:

1. **Select the backend identifier**. Choose one of the supported strings (e.g., `"pgvector"`, `"qdrant"`, `"faiss"`). This value becomes the `backend` parameter in your `VectorStore` constructor.

2. **Provide backend-specific configuration**. Pass a dictionary containing connection parameters via the `config` argument. 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_store` method unpacks these values when initializing the concrete store.

3. **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 informative `ImportError` directing 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

```python
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.

```python
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:

```python
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`](https://github.com/semantica-agi/semantica/blob/main//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 `VectorStore` façade in [`/semantica/vector_store/vector_store.py`](https://github.com/semantica-agi/semantica/blob/main//semantica/vector_store/vector_store.py) abstracts all backend implementations behind a unified interface controlled by the `backend` parameter and `config` dictionary.
- **Zero code changes**: You can migrate from FAISS to pgvector, Qdrant, or Pinecone by only modifying initialization arguments, leaving all `store_vectors()` and `search_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`, or `weaviate` based 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.