ELIPS is an embedded, local-first vector database. No server to run — just open a path and start searching. Five minutes to your first semantic search.
What is ELIPS?
ELIPS (Embedded Local Index & Persistence System) is a C++23 library that gives you an in-process vector database with the same deployment philosophy as SQLite: open a file, use it, close it. No daemon, no network, no container.
- Embedded: ships as a shared/static library + Python extension. Zero external services.
- Persistent: WAL-backed on-disk storage with crash recovery. Also works fully in-memory.
- Fast: HNSW graph index for ANN search; a FAISS-style Index API (IndexFlat/IVF/HNSW, bf_knn); optional GPU acceleration (Metal today, CUDA/HIP experimental).
- Flexible: cosine, Euclidean, dot-product metrics; metadata filtering; hybrid vector+lexical search; EQL query language.
Install
Build from the repository — there is no PyPI wheel yet:
# 1. Clone and configure
git clone https://github.com/axiomchronicles/elips
cd elips
cmake -S . -B build -G Ninja \
-DELIPS_ENABLE_PYTHON=ON \
-DCMAKE_BUILD_TYPE=Release
# 2. Build
cmake --build build --target elips_pymodule -j$(nproc)
# 3. Put the package on PYTHONPATH
export PYTHONPATH=$PWD/bindings/python
# 4. Verify
python -c "import elips; print(elips.__version__)"
# 1.1.0For GPU support add -DELIPS_ENABLE_GPU=ON (Metal is default-on on Apple). See Installation for full toolchain requirements.
Hello world (in-memory)
Open an in-memory database, write three records, and run a text search — no embedder configuration required:
import elips
# Open an in-memory client. Dimension=2 for demo.
# The built-in local text embedder auto-attaches.
client = elips.Client(dimension=2)
docs = client.get_or_create_collection("documents")
# Add records with text + metadata
docs.add(
documents=[
"alpha design note",
"beta deployment runbook",
"gamma security policy",
],
metadatas=[
{"kind": "design", "year": 2024},
{"kind": "ops", "year": 2023},
{"kind": "security", "year": 2024},
],
)
# Text search — returns Hit objects sorted by similarity
hits = docs.query(query_texts="alpha", n_results=2)
for hit in hits:
print(hit.text, hit.distance, hit.meta)
client.close()
# Output (approx):
# alpha design note 0.0 {'kind': 'design', 'year': 2024}
# gamma security policy 0.42 {'kind': 'security', 'year': 2024}What just happened: Client() auto-attached the built-in local text embedder. add(documents=...) embedded the text and stored both the vector and the source text. query(query_texts=...) embedded the query and ran ANN search.
Persistent database
Pass a filesystem path instead of ":memory:". The database persists across process restarts:
import elips, tempfile
path = tempfile.mkdtemp()
# Write session
with elips.PersistentClient(path, dimension=128) as client:
papers = client.get_or_create_collection("papers")
key = papers.add(
embeddings=[[0.1] * 128],
metadatas=[{"title": "Attention is all you need", "year": 2017}],
)
client.checkpoint() # flush WAL to snapshot
print("wrote key:", key)
# Reopen and search
with elips.PersistentClient(path) as client:
papers = client.get_collection("papers")
print("count after reopen:", papers.count())
# 1 — record survived the restartELIPS writes mutations to a WAL (wal.log) before acknowledging them. On reopen it replays the WAL on top of the last snapshot. checkpoint() merges the WAL into the snapshot and truncates the log.
Custom embedder
Bring your own model — anything that turns a list of strings into a list of float vectors:
import elips
from sentence_transformers import SentenceTransformer
# Load model once, outside connect()
model = SentenceTransformer("all-MiniLM-L6-v2") # dim=384
def embed(texts: list[str]) -> list[list[float]]:
return model.encode(texts, normalize_embeddings=True).tolist()
client = elips.Client(
dimension=384,
metric="cosine",
embedder=embed,
embedder_provider="sentence-transformers",
embedder_model="all-MiniLM-L6-v2",
use_default_text_embedder=False, # don't auto-attach builtin
)
docs = client.get_or_create_collection("docs")
docs.add(documents=["Machine learning fundamentals", "Neural network architecture"])
hits = docs.query(query_texts="deep learning basics", n_results=2)
print(hits[0].text) # Machine learning fundamentals
client.close()Metadata filtering
Combine vector search with metadata predicates using the Filter API:
import elips
client = elips.Client(dimension=2)
articles = client.get_or_create_collection("articles")
articles.add(
embeddings=[[1.0, 0.0], [0.9, 0.1], [0.8, 0.2]],
metadatas=[
{"kind": "design", "year": 2024, "author": "alice"},
{"kind": "ops", "year": 2023, "author": "bob"},
{"kind": "design", "year": 2023, "author": "carol"},
],
)
# Only design articles from 2024+
f = elips.Filter().field("kind").equals("design").field("year").gte(2024)
hits = articles.query(query_embeddings=[1.0, 0.0], n_results=10, where=f)
print([h.meta["author"] for h in hits]) # ['alice']
# OR combinator: design OR ops from 2023+
f2 = (
elips.Filter().field("kind").equals("design")
.or_(elips.Filter().field("kind").equals("ops"))
.and_(elips.Filter().field("year").gte(2023))
)
hits2 = articles.query(query_embeddings=[1.0, 0.0], n_results=10, where=f2)
print(len(hits2)) # 3
client.close()Hybrid search
Blend vector similarity with lexical (keyword) overlap by passing both query_embeddings and query_texts to query():
import elips
client = elips.Client(dimension=2)
docs = client.get_or_create_collection("docs")
docs.add(
embeddings=[[1.0, 0.0], [0.5, 0.5], [0.9, 0.1]],
documents=[
"ELIPS vector database overview",
"PostgreSQL relational database",
"ELIPS GPU acceleration guide",
],
)
# Hybrid: vector score blended with lexical overlap on "ELIPS"
hits = docs.query(
query_embeddings=[1.0, 0.0],
query_texts="ELIPS",
n_results=3,
lexical_weight=0.25,
)
print([h.text for h in hits])
# ELIPS records rank higher due to lexical boost
client.close()Transactions
Group multiple writes into an atomic batch — all succeed or none apply:
import elips
client = elips.Client(dimension=2)
# begin_transaction() lives on the native Database handle
with client.native.begin_transaction() as txn:
docs_txn = txn.vault("documents")
ops_txn = txn.vault("ops-logs")
k1 = docs_txn.place([1.0, 0.0], {"title": "Proposal"})
k2 = ops_txn.place([0.5, 0.5], {"event": "proposal_created", "doc_id": k1})
# txn.commit() called automatically on clean exit
# txn.rollback() called automatically on exception
client.close()GPU acceleration
If your build includes GPU support, select a backend with the device string. Metal is the implemented path (Beta, validated on Apple M4) on Apple silicon; CUDA and HIP are experimental:
import elips
if not elips.has_gpu:
raise RuntimeError("build without -DELIPS_ENABLE_GPU=ON")
# Discover accelerators
for spec in elips.accelerators():
print(spec.name, spec.backend, spec.memory_bytes)
# Open on a specific backend (raises BackendUnavailableError if absent,
# unless fallback=True demotes to CPU)
with elips.Client(dimension=1024, metric="cosine", device="metal") as client:
print(client.native.gpu_info().backend) # "metal" on Apple silicon
embeddings = client.get_or_create_collection("embeddings")
# ... add vectors, query as normal — the GPU handles the distance math
# Exact brute-force on the GPU, no index build:
import numpy as np
xb = np.random.rand(100_000, 128).astype("float32")
xq = np.random.rand(10, 128).astype("float32")
D, I = elips.bf_knn(xq, xb, 10, metric="l2", device="metal")Next steps
- Collection reference — full method documentation with all parameters
- Client reference — all configuration options
- Filtering — Filter API in depth
- Config & HnswParams — HNSW tuning, durability, access modes
- GPU overview — GPU backends, memory, maturity
- Guides — task-shaped walkthroughs for common workflows
- EQL — query language for complex programmatic queries
- C++ quick start — embed ELIPS directly in C++23 applications