Most LlamaIndex setups end up with two separate backends once you go beyond plain vector search: a vector store for VectorStoreIndex, and a separate graph database for PropertyGraphIndex when you need relationship-aware retrieval (GraphRAG). Two services, two connection strings, two things to keep in sync.
This is a walkthrough of backing both index types with SynapCores instead — one engine, one connection, both index types.
Setup
docker run -d --name synapcores -p 8080:8080 \
-e AIDB_ACCEPT_LICENSE=1 \
-v synapcores-data:/var/lib/synapcores \
ghcr.io/synapcores/community:latest
pip install llama-index llama-index-vector-stores-synapcores llama-index-graph-stores-synapcores
Both integration packages are independently published on PyPI:
Vector store — standard RAG
from llama_index.core import VectorStoreIndex, StorageContext, Document
from llama_index.vector_stores.synapcores import SynapCoresVectorStore
vector_store = SynapCoresVectorStore(uri="http://localhost:8080", embedding_dim=1536)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
docs = [Document(text="SynapCores runs vector search, graph traversal, and SQL in one engine.")]
index = VectorStoreIndex.from_documents(docs, storage_context=storage_context)
query_engine = index.as_query_engine()
response = query_engine.query("What does SynapCores combine into one engine?")
print(response)
The vector store implements the full BasePydanticVectorStore ABC — add, delete, query, delete_nodes, clear, plus the async surface. Metadata filtering supports the full MetadataFilters grammar: all 12 operators (EQ, NE, GT/GTE/LT/LTE, IN, NIN, TEXT_MATCH, TEXT_MATCH_INSENSITIVE, CONTAINS, IS_EMPTY) with AND/OR/NOT and nested groups — so you're not giving up filtering power by moving off a dedicated vector DB.
If you already have data in SynapCores from a previous run:
index = VectorStoreIndex.from_vector_store(vector_store)
Property graph store — GraphRAG
This is the part that usually needs a second database. Not here:
from llama_index.core import PropertyGraphIndex
from llama_index.graph_stores.synapcores import SynapCoresPropertyGraphStore
graph_store = SynapCoresPropertyGraphStore(uri="http://localhost:8080")
graph_index = PropertyGraphIndex.from_documents(
docs,
property_graph_store=graph_store,
)
retriever = graph_index.as_retriever()
nodes = retriever.retrieve("What connects to SynapCores?")
The graph store implements the full PropertyGraphStore ABC with both supports_structured_queries=True and supports_vector_queries=True — including get_rel_map(depth=N), the depth-bounded BFS primitive that PropertyGraphIndex.as_retriever() actually depends on under the hood. structured_query() passes Cypher straight through with named-parameter binding if you want to write graph queries by hand instead of relying on the auto-extracted schema.
Why bother
The two index types above are hitting the same SynapCores instance, over the same connection — a vector table and a graph both living in one engine, not stitched together after the fact with a sync job. If you're prototyping GraphRAG and don't want to stand up Neo4j just to try it, or you want vector and graph retrieval to compose in a single query without cross-service joins, this is what that looks like end to end.
Test coverage, for anyone evaluating this seriously
48 tests against a live engine via docker-compose (23 vector + 25 graph), plus runnable notebooks with real HuggingFace MiniLM embeddings (384 dims):
- Source + tests: github.com/SynapCores/synapcores-llamaindex
- Notebooks: notebooks directory
Both packages are maintained independently of the LlamaIndex monorepo and published straight to PyPI, so pip install is all you need — no waiting on a docs PR to land anywhere.
Top comments (0)