Neo4j GraphRAG: Entity Extraction, Graph Retrieval, Communities, and Query Planning
Neo4j's GraphRAG stack is a set of tools — the neo4j-graphrag Python package, the Graph Data Science (GDS) library, and the LLM Knowledge Graph Builder — for turning unstructured text into a queryable entity graph and retrieving from it with a mix of vector search, full-text search, graph traversal, and LLM-generated Cypher. It sits apart from Microsoft's GraphRAG in one structural way: Microsoft's design is a corpus-indexing algorithm that produces community summaries for global questions, while Neo4j's package is a retrieval and construction toolkit built directly on top of a general-purpose graph database, exposing the underlying Cypher queries at every step rather than treating retrieval as a single opaque call. The two are not mutually exclusive — the neo4j-contrib/ms-graphrag-neo4j project imports Microsoft's own GraphRAG output into Neo4j for querying and visualization — but the native package assumes you want direct control over schema, extraction prompts, and query plans.
········
THE KNOWLEDGE GRAPH CONSTRUCTION PIPELINE: FROM TEXT TO ENTITY GRAPH.
How raw documents become nodes, relationships, and the embeddings that make them searchable.
Construction runs as a pipeline, typically driven by the package's SimpleKGPipeline class: documents are chunked, each chunk is passed to an LLM along with a user-supplied schema of allowed node and relationship types, and the model returns entities and relationships as structured output. Constraining extraction to a declared schema is what keeps the graph from turning into an unbounded set of ad hoc entity types — without one, the LLM will name entities and relations however it sees fit, which fragments the graph and hurts downstream retrieval. Extracted entities are deduplicated through entity resolution, which merges mentions of the same real-world thing across chunks using string similarity, embedding similarity, or a custom resolver function supplied by the developer. The pipeline keeps two graphs linked to each other: a lexical graph of document chunks (for provenance and text retrieval) and a domain graph of entities and relationships (for structural queries), so any entity found later during retrieval can be traced back to the source chunk it came from.
........
Stage | What happens | Tooling / configuration |
Chunking | Source documents split into passages sized for LLM context windows | Configurable splitter (fixed-size or custom) |
Entity & relation extraction | LLM reads each chunk against a supplied schema and emits entities and relationship triples | SimpleKGPipeline + schema definition; OpenAI, Anthropic, Gemini, Vertex AI, Cohere, MistralAI, Bedrock, or Ollama as the LLM |
Entity resolution | Merges duplicate mentions of the same entity found across different chunks | String similarity, embedding similarity, or a custom resolver function |
Graph writing | Persists chunks, entities, and relationships as linked nodes in Neo4j | Cypher writes issued by the pipeline; lexical graph and domain graph kept distinct but cross-referenced |
Embedding & indexing | Chunks (and optionally entity/community summaries) are embedded and indexed for vector search | Native Neo4j vector index; OpenAI or Gemini embeddings, or local sentence-transformers models |
Community detection (optional) | Groups entities into hierarchical clusters and generates an LLM summary per cluster | Neo4j Graph Data Science library: WCC, Louvain, or Leiden algorithms |
........
········
RETRIEVAL STRATEGIES: VECTOR, HYBRID, GRAPH TRAVERSAL, AND TEXT2CYPHER.
What each retriever class in the Python package actually does and where it breaks down.
The package exposes retrieval as separate, composable classes rather than a single retrieval mode. VectorRetriever embeds the query and searches Neo4j's native vector index for the nearest chunks — plain semantic search, with the usual weakness that exact strings like dates, product codes, or domain-specific identifiers don't embed distinctively and can be missed. HybridRetriever runs the same query against both a vector index and a full-text (BM25-style) index, normalizes the two score distributions, and merges the ranked results, which recovers exact-match cases the vector-only path drops. VectorCypherRetriever and HybridCypherRetriever add a graph-traversal step after the initial vector or hybrid match: once candidate chunks or entities are found, a supplied Cypher fragment walks outward across relationships to pull in connected entities, multi-hop context, or aggregated properties that don't live in the matched chunk itself — this is the mechanism that actually makes retrieval "graph" rather than "vector plus metadata." Text2CypherRetriever skips vector matching entirely: it sends the database schema and the user's question to an LLM, gets back a Cypher query, executes it, and returns the structured result — appropriate for questions that resolve to a precise structural query (counts, filters, aggregations) rather than a fuzzy semantic match.
Text2Cypher is also the least reliable link in the chain. Accuracy depends heavily on schema size and the LLM used: large schemas can exceed what a model reliably reasons over, which pushes toward sub-schema retrieval (narrowing the schema to relevant node and relationship types before generation) rather than exposing the full graph model on every call. Neo4j's own guidance treats it as suited to low-complexity or infrequent queries and as a fallback tool, not as the primary path for complex queries run at volume — those are better served by prewritten, parameterized Cypher templates. Recommended mitigations include injecting few-shot question-to-query examples via vector similarity, using models fine-tuned on validated Cypher datasets, and running generated queries through deterministic validation (regex checks, or libraries like CyVer) before execution rather than trusting the LLM's output directly. None of this is unique to Neo4j — it's the same class of problem as text-to-SQL — but it means query-planning accuracy is a tuning and evaluation cost the schema-and-prompt-engineering side of the project has to carry, separate from the extraction pipeline's cost.
········
COMMUNITY DETECTION AND GLOBAL SEARCH: LEIDEN, SUMMARIES, AND COST.
How clustering and summarization are made cheaper than Microsoft's original design, and what that trades away.
For questions that span the whole corpus rather than a specific entity — "what are the recurring themes across these documents" — entity-level retrieval doesn't work; the answer requires a summary of a cluster of related entities. Neo4j builds this using the Graph Data Science library's community-detection algorithms (weakly connected components as a first pass, then Louvain or Leiden) run over the entity graph projected as a weighted network, with edge weight reflecting how often two entities co-occur. Leiden produces hierarchical communities — coarse clusters at low resolution, finer sub-clusters at higher resolution — and the pipeline can retrieve every level via the includeIntermediateCommunities parameter. Each community gets an LLM-generated natural-language summary built from its members' extracted properties and relationships, and a "community rank" derived from how many distinct source documents its members appear in, which is used to prioritize which summaries get pulled into context for a global query.
The cost divergence from Microsoft's original GraphRAG design is structural, not incidental. Microsoft's approach generates an LLM summary for every individual entity and every individual relationship at indexing time, in addition to community summaries — a documented third-party implementation reported roughly 29,000 LLM calls to summarize a graph of about 13,000 entities and 16,000 relationships. The Neo4j/LangChain implementation described in Neo4j's own developer blog instead summarizes only selected levels of the community hierarchy (for example, levels 0, 1, and 4) rather than every level and every individual element, cutting the summarization call count sharply for the same graph size. That same write-up estimated roughly $30 in GPT-4o costs for entity extraction alone across 2,000 articles — a single documented example, not a vendor-published benchmark, and one that will shift with model pricing and article length. The trade-off is real: skipping intermediate hierarchy levels means some queries that would have matched a mid-granularity community summary in the exhaustive approach have to be answered from a coarser or finer level instead, which can lose nuance on edge-case questions even as it cuts indexing cost.
........
Approach | Summarization scope | Relative LLM call volume | Trade-off |
Microsoft GraphRAG (original design) | Every entity and every relationship individually, plus every community level | ~29,000 calls reported for ~13,000 entities / ~16,000 relationships (third-party implementation) | Most complete summaries; indexing cost scales directly with corpus size regardless of query pattern |
Neo4j / LangChain implementation | Only selected community hierarchy levels (e.g., 0, 1, 4), not every entity or relationship | Substantially lower than the exhaustive approach on the same graph, per the same write-up | Cheaper, faster indexing; some intermediate granularity is skipped, which can weaken answers to edge-case queries |
........
········
WHERE NEO4J GRAPHRAG FITS: LICENSING, COST, AND THE DECISION RULE.
What running this stack actually costs to operate, and when the added machinery is justified.
The neo4j-graphrag package itself is Apache 2.0 and free, supporting Python 3.10 through 3.14 (the optional NLP extra is unsupported on 3.14 due to an upstream spaCy issue as of the current release). The cost is in the database and the graph algorithms layer around it. Self-hosted Neo4j Community Edition is free under GPL3, but its bundled Graph Data Science capability is capped — limited CPU parallelism and a restricted algorithm/model catalog — and Enterprise Edition, which requires a sales-negotiated license, removes those caps and adds unlimited horizontal read scaling. On the managed side, AuraDB Free exists for prototyping with no credit card, AuraDB Professional starts at $65/GB/month with a 1GB minimum and scales to 128GB RAM per instance, and AuraDB Business Critical runs $146/GB/month with multi-zone deployment and a 99.95% uptime SLA; native vector indexing is available from the Professional tier upward, according to Neo4j's published pricing page. Community detection at scale means running GDS, so the effective cost of global search includes whichever GDS tier — capped Community or licensed Enterprise — your community-detection workload actually needs, on top of whatever LLM calls the extraction and summarization steps consume.
Reach for Neo4j GraphRAG when the questions you need to answer depend on relationships the source text doesn't state in one place — multi-hop connections, thematic roll-ups across many documents, or queries where the answer is structurally precise (counts, paths, filters) rather than semantically similar — and where you're willing to maintain a schema, an entity-resolution step, and, for global search, a GDS-based community pipeline. Default to a plain vector store instead when relevance is determined by semantic similarity within individual documents or chunks: standing up entity extraction, resolution, and graph algorithms adds real engineering and licensing overhead that a flat vector index simply does not carry, and that overhead only pays for itself once the graph structure is doing retrieval work a vector index structurally cannot.
········
FOLLOW US FOR MORE.
·····
DATA STUDIOS
·····



