Graph RAG with FalkorDB: A Practical Setup Guide
FalkorDB is the lightweight, Redis-based graph store quietly powering more graph RAG stacks than Neo4j in 2026. A practical setup guide: install, schema, ingest, query.
By Tulasinath Reddy · March 18, 2026 · Tags: Graph RAG Tutorial FalkorDB
FalkorDB started life as RedisGraph and is now the lightweight, single-binary alternative to Neo4j for graph workloads. For RAG specifically, it has three things going for it: sub-millisecond traversal latency, zero operational overhead beyond Redis you already run, and a Cypher-compatible query language. This is a practical setup guide — not a marketing pitch.
If graph RAG is new to you, start with What Is Graph RAG?
Why FalkorDB for graph RAG
- Latency. Single-digit-millisecond traversal on graphs up to ~50M nodes. Faster than Neo4j Community for the small-traversal patterns RAG actually does.
- Footprint. One Redis container. No JVM, no JVM heap tuning, no Java GC pauses interrupting queries.
- Mental model. If your team already runs Redis, FalkorDB is a Redis module — same ops story, same client libraries.
- Cost. Open source under SSPL. Hosted offering exists if you want it managed.
Tradeoffs: smaller community than Neo4j, fewer GUI tools, no built-in graph algorithms library (you'll write traversals yourself). For RAG retrieval those don't matter; for analytics they might.
Install (60 seconds)
docker run -d -p 6379:6379 falkordb/falkordb:latestThat's it. FalkorDB now responds to standard Redis commands plus the GRAPH.QUERY command for Cypher.
Schema design for RAG
The canonical RAG schema has three node types and three relationship types. Keep it simple — over-modeling at this layer makes retrieval slower without adding accuracy:
// Node types
(:Document {id, title, source_url, ingested_at})
(:Chunk {id, text, doc_id, position, embedding_vector})
(:Entity {id, name, type}) // type ∈ {Person, Org, Place, Concept, ...}
// Edge types
(Document)-[:HAS_CHUNK]->(Chunk)
(Chunk)-[:MENTIONS]->(Entity)
(Entity)-[:RELATES_TO {label}]->(Entity)
The RELATES_TO edge carries a label property ("works_at", "founded", "located_in") rather than encoding every relationship type as its own edge type. This keeps the schema bounded; you don't end up with 400 edge types after a month of ingest.
Ingest pattern
import falkordb
client = falkordb.FalkorDB(host='localhost', port=6379)
g = client.select_graph('vertexrag_kb')
# 1. Insert document + chunks
for chunk in chunks_from_document(doc):
g.query('''
MERGE (d:Document {id: $doc_id}) SET d.title = $title
CREATE (c:Chunk {id: $cid, text: $text, position: $pos})
CREATE (d)-[:HAS_CHUNK]->(c)
''', params={'doc_id': doc.id, 'title': doc.title,
'cid': chunk.id, 'text': chunk.text, 'pos': chunk.idx})
# 2. Insert entities + relationships from LLM extraction
triples = extract_triples_with_llm(chunk.text) # [(subj, pred, obj), ...]
for s, p, o in triples:
g.query('''
MERGE (e1:Entity {name: $s}) ON CREATE SET e1.id = randomUUID()
MERGE (e2:Entity {name: $o}) ON CREATE SET e2.id = randomUUID()
MERGE (e1)-[r:RELATES_TO {label: $p}]->(e2)
WITH e1, e2
MATCH (c:Chunk {id: $cid})
MERGE (c)-[:MENTIONS]->(e1)
MERGE (c)-[:MENTIONS]->(e2)
''', params={'s': s, 'p': p, 'o': o, 'cid': chunk.id})
The MERGE on entity name is the trick — it deduplicates mentions across documents automatically. "OpenAI" appearing in 80 chunks becomes one node with 80 inbound :MENTIONS edges.
Query pattern (multi-hop retrieval)
# 1. Vector seed (against your separate vector store)
seed_chunks = vector_store.search(query_embedding, k=5)
# 2. Graph expansion — find chunks that share entities with the seed set
cypher = '''
MATCH (c:Chunk)-[:MENTIONS]->(e:Entity)
WHERE c.id IN $seed_ids
WITH DISTINCT e
MATCH (e)-[:RELATES_TO*1..2]-(neighbor:Entity)<-[:MENTIONS]-(related:Chunk)
WHERE related.id NOT IN $seed_ids
RETURN related.text AS text, count(*) AS path_score
ORDER BY path_score DESC LIMIT 8
'''
expansion = g.query(cypher, params={'seed_ids': [c.id for c in seed_chunks]})
all_chunks = seed_chunks + expansion.result_set
The *1..2 in the path pattern means "follow 1 or 2 RELATES_TO hops" — that's the dial that controls multi-hop depth. Higher numbers explode the candidate set; 2 is the sweet spot for most RAG workloads.
Production gotchas
- Persist Redis. Configure AOF or RDB persistence; otherwise a Redis restart wipes your graph.
- Index
Entity.nameandChunk.id.CREATE INDEX FOR (e:Entity) ON (e.name). Without indexes, large MERGE operations get slow fast. - Cap edge degree. A handful of "hub" entities (large companies, common concepts) accumulate thousands of edges and dominate traversal cost. Either prune their edges or weight them down at retrieval time.
- Memory is the limit. FalkorDB is in-memory. Plan for ~250 bytes per node and ~150 bytes per edge as a rough back-of-envelope.
Skip the operations
The VertexRAG API runs FalkorDB plus a vector store plus the entire ingest + retrieval pipeline behind one REST call. Same engine; you skip the schema design, the Cypher-tuning, and the Redis persistence config. Worth a look if you want graph RAG without operating it.
Read more on the VertexRAG blog or try the Graph RAG API.