DEV Community

Jangwook Kim
Jangwook Kim

Posted on Originally published at effloow.com

LightRAG vs Microsoft GraphRAG in 2026: The Costs We Could Verify and the Benchmark Numbers We Would Not Invent

Why We Compared LightRAG and Microsoft GraphRAG

We brought LightRAG and Microsoft GraphRAG into our review because graph retrieval creates a budgeting problem before it creates a retrieval advantage.

A vector index is relatively easy to cost. We chunk documents, embed the chunks, store the vectors, and pay for one generation request per query. For LightRAG, we budget for index-time LLM entity and relationship extraction and profiling, alongside deduplication and embeddings. Full Microsoft GraphRAG also builds hierarchical communities and generates community reports before serving queries. LazyGraphRAG follows a different pattern: it builds its concept graph without LLM calls and defers LLM work until query time.

The architectural distinction matters.

LightRAG builds a graph of entities and relationships alongside vector indexes. Its local retrieval mode targets specific entities and their connections. Its global mode retrieves broader concepts and themes. It avoids Microsoft GraphRAG's full hierarchy of precomputed community reports, which reduces indexing work but does not make indexing free. Entity and relationship extraction still consume prompt and completion tokens.

Microsoft GraphRAG's full indexing pipeline is heavier. It extracts entities and relationships, consolidates descriptions, detects hierarchical communities, and generates summaries used by global search. Local search combines graph records with source text. Global search performs map-reduce-style reasoning over community reports.

LazyGraphRAG is a separate cost model, not a cheaper name for the same pipeline. It uses noun-phrase extraction and graph statistics during indexing, skips LLM-generated community summaries, and defers LLM work until query time. That can radically lower initial indexing cost while making query cost dependent on relevance-test budgets and the number of subqueries.

Our central question was therefore not, “Which graph system is fastest?” It was:

Does the quality gain from graph retrieval repay the indexing bill and additional operational complexity at the expected query volume?

For a repeatable comparison, we would freeze a 20–50-document corpus, separate local and global query classes, and use a common chat model and embedding model. We would record wall-clock indexing time, LLM request count, input and output tokens, estimated API spend, cold and warm query latency, and evidence-grounded answer quality.

We do not have a complete, defensible four-way numeric ledger. We could inspect the historical comparison's setup, but not its numerical results. Our only fully reproduced experiment concerned requirement parsing for a document-ingestion dependency. We will not convert missing measurements into plausible-looking benchmark data.

That limitation is itself useful. We identified several comparability risks: version differences, a changed chat-model tier, and a single-file literary corpus. We also could not establish whether prompts, chunking, and query text stayed identical between the historical rounds. Those limits prevent us from transferring their costs directly to a production budget.

Hands-On Walkthrough: Setup, Execution & Output

We verified that the current packaged LightRAG distribution is named lightrag-hku, not lightrag. For server installation, the API extra is the relevant path:

python -m venv .venv
source .venv/bin/activate

python -m pip install --upgrade pip
python -m pip install "lightrag-hku[api]"

cp env.example .env
# Configure the LLM, embedding provider, dimensions, and authentication.
lightrag-server
Enter fullscreen mode Exit fullscreen mode

For library use, install the base package:

python -m pip install lightrag-hku
Enter fullscreen mode Exit fullscreen mode

For Microsoft GraphRAG, we initialized a project root, placed source documents under the configured input directory, and used its indexing CLI:

python -m venv .venv-graphrag
source .venv-graphrag/bin/activate

python -m pip install graphrag
graphrag init --root ./graphrag-workspace

# Edit settings.yaml and place text files in the configured input directory.
graphrag index --root ./graphrag-workspace

graphrag query \
  --root ./graphrag-workspace \
  --method local \
  --query "Which components depend on the Atlas gateway?"

graphrag query \
  --root ./graphrag-workspace \
  --method global \
  --query "What recurring operational risks appear across the corpus?"
Enter fullscreen mode Exit fullscreen mode

For reproducible cost accounting, we would count requests at the HTTP client boundary rather than infer them from framework log lines. We would track retries separately and use provider-returned usage fields to determine token spend. We would tag chat and embedding requests by phase and measure wall time with a monotonic clock.

The ledger needs at least these fields:

{
  "engine": "lightrag",
  "version": "pinned-version-or-commit",
  "phase": "index",
  "operation": "entity_relation_extraction",
  "request_count": 1,
  "input_tokens": 2941,
  "output_tokens": 612,
  "retry_count": 0,
  "elapsed_ms": 1842,
  "model": "configured-chat-model"
}
Enter fullscreen mode Exit fullscreen mode

This JSON object illustrates a proposed ledger format; its values are placeholders, not benchmark results.

We also isolated the ingestion failure associated with the historical textract path. The following check is runnable and reproduces the requirement-parser problem without downloading or installing the affected document parser:

from packaging.requirements import Requirement, InvalidRequirement
from packaging.version import Version

requirements = [
    "extract-msg<=0.29.*",
    "extract-msg<=0.29",
    "extract-msg<0.30",
    "extract-msg==0.29.*",
]

for value in requirements:
    try:
        parsed = Requirement(value)
        print(f"ACCEPTED {value}: {parsed.specifier}")
    except InvalidRequirement as exc:
        print(f"REJECTED {value}: {type(exc).__name__}")

versions = ["0.28.9", "0.29", "0.29.1", "0.30"]
for specifier in ["<=0.29", "<0.30", "==0.29.*"]:
    requirement = Requirement(f"extract-msg{specifier}")
    accepted = {
        version: Version(version) in requirement.specifier
        for version in versions
    }
    print(specifier, accepted)
Enter fullscreen mode Exit fullscreen mode

With Python 3.12.14 and packaging==24.2, our output was:

REJECTED extract-msg<=0.29.*: InvalidRequirement
ACCEPTED extract-msg<=0.29: <=0.29
ACCEPTED extract-msg<0.30: <0.30
ACCEPTED extract-msg==0.29.*: ==0.29.*
<=0.29 {'0.28.9': True, '0.29': True, '0.29.1': False, '0.30': False}
<0.30 {'0.28.9': True, '0.29': True, '0.29.1': True, '0.30': False}
==0.29.* {'0.28.9': False, '0.29': True, '0.29.1': True, '0.30': False}
Enter fullscreen mode Exit fullscreen mode

This check does not prove that a patched textract installation can parse PDF or Office files. It proves only that the malformed wildcard constraint is rejected and that casually deleting the wildcard changes dependency semantics.

In a repeatable benchmark, we would treat local and global modes separately rather than combine retrieval and answer generation into one opaque timer. We would record these phases for each query:

  1. Query preprocessing or keyword extraction.
  2. Query embedding.
  3. Graph and vector retrieval.
  4. Context construction.
  5. Answer generation.
  6. Total end-to-end latency.

That separation matters because a “fast retrieval” result can still produce a slow answer when the retrieved graph context is large.

Teams building a repeatable evaluation can adapt this ledger to their own stack or use our broader tools collection as a starting point.

Version, Configuration, and Operational Limitations

The first problem was version comparability.

In our version review, we kept the paper-era architecture separate from the broader 2026 package, which includes multiple chunking strategies, role-specific model configuration, reranking, multimodal parsing, several storage backends, and deletion workflows. We identified two distinct historical setups: an unpinned LightRAG source checkout paired with Microsoft GraphRAG 0.5.0, and a LightRAG 1.2.5 evaluation requiring internal patches to return retrieved context.

Those are not interchangeable systems. We would not compare a current LightRAG build against GraphRAG 0.5.0 and call the result a 2026 product benchmark.

The second configuration check is embedding compatibility. We would pin the embedding model, output dimensions, vector-store schema, and query-time embedding configuration together. We verified that the historical comparison selected text-embedding-3-small, but we did not establish the dimensions configured for either engine or test dimension-mismatch behavior. We would validate any model or dimension change as an index migration before deployment.

Third, graph extraction cost is controlled more by chunks than by files. A 20-file corpus can become hundreds of extraction prompts if files are long, chunk size is small, overlap is high, or extraction retries are enabled. “Cost per document” is therefore the wrong planning unit.

Our useful planning approximation is:

index cost =
  extraction input tokens
  + extraction output tokens
  + entity/relation consolidation tokens
  + community-summary tokens
  + embedding tokens
  + retry overhead
Enter fullscreen mode Exit fullscreen mode

LightRAG removes some of the community-report work associated with full GraphRAG, but it still pays for graph extraction and profile generation. Full GraphRAG adds community summarization, which can dominate a small corpus because fixed prompt scaffolding is repeated across many operations.

Fourth, document ingestion is separate from retrieval architecture. The malformed extract-msg<=0.29.* constraint was an immediate blocker on the older textract path. We did not accept “remove the asterisk” as a safe fix. As our parser check showed, <=0.29 rejects 0.29.1, while <0.30 admits it. The correct repair depends on the dependency author's intended range and requires parser regression tests.

For production, we prefer explicit ingestion adapters for plain text, Markdown, PDF, and Office files over a large transitive parser bundle. We persist normalized text and document hashes before either graph engine sees the content.

Fifth, incremental insertion is not the same as editing. LightRAG can process a new document without rebuilding the whole corpus. For an existing document edit, however, we need deterministic document IDs, deletion or invalidation of old chunks, and regeneration of affected graph records. Cache reuse can reduce work, but it does not guarantee zero extraction calls.

GraphRAG 0.5.0 introduced incremental update support, yet its behavior still needs testing against the exact current release and storage configuration. We did not retain a valid measurement for the number of calls caused by a one-document edit, so we will not assign a percentage saving.

Finally, LightRAG's default local KV, vector, and graph stores are suitable for evaluation, not a production capacity test. File-backed persistence surviving a restart does not make those stores equivalent to PostgreSQL, Neo4j, OpenSearch, or another networked backend. We must benchmark production I/O, locking, backup, and concurrent-query behavior on the backend we intend to operate.

Scale, Latency & Cost vs. Alternatives

Here is the comparison we can defend. “Not established” means the test artifacts did not support a trustworthy number—not that the operation has zero cost.

Option Index-time work Query-time pattern Measured wall time and latency Measured request and token spend Best fit
LightRAG local Entity and relation extraction, profiling, deduplication, embeddings Entity-focused graph and vector retrieval, then generation Not established Not established in a complete retained run Questions about named entities and connected facts
LightRAG global Same shared LightRAG index Theme-level retrieval over graph-derived keys, then generation Not established in a complete retained run Not established in a complete retained run Broad questions where full GraphRAG reports are too expensive
GraphRAG local Extraction, consolidation, graph construction, embeddings, and supporting summaries Entity and source-text context, then generation Not established in a complete retained run Not established in a complete retained run Rich entity-centric investigation
GraphRAG global Full graph plus hierarchical community reports Map-reduce reasoning over community reports Not established in a complete retained run Not established in a complete retained run Corpus-wide synthesis where breadth is worth the cost
LazyGraphRAG NLP concept extraction and graph statistics, without index-time LLM summarization Deferred relevance testing, claim extraction, and answer reduction We did not verify it as a comparable open-source CLI mode We did not reproduce Microsoft's numeric claims Cost-sensitive global retrieval with higher query-time variability
Vector-only RAG Chunk embeddings Similarity search and one answer-generation path Must be measured on the same corpus and model Usually the lowest indexing bill Local questions and small corpora

In our cost-model review, we kept LazyGraphRAG's indexing claim separate from query cost: indexing matched vector RAG and cost 0.1% of full GraphRAG indexing in the research configuration. We also examined lower-query-cost configurations, but did not reproduce those results. We keep both claims scoped to 5,590 news articles, 100 synthetic queries, specific relevance-test budgets, and LLM-based pairwise quality judgments.

That scale is fundamentally different from the proposed 20–50-document benchmark.

For a buyer, the correct break-even calculation is:

break-even queries =
  (graph index cost - vector index cost)
  /
  (vector cost per query - graph cost per query)
Enter fullscreen mode Exit fullscreen mode

If graph queries cost more than vector queries, there is no cost-only break-even. The graph system must produce enough quality improvement to reduce human review, failed answers, escalations, or downstream agent retries.

We also calculate edit break-even separately:

monthly total =
  initial index cost
  + monthly update cost
  + query count × query cost
  + storage and operations cost
Enter fullscreen mode Exit fullscreen mode

There is no universal minimum corpus size at which graph indexing begins to pay. Document count is a weak proxy. Relationship density, cross-document dependencies, query mix, update frequency, and error cost matter more.

For fewer than roughly a few dozen documents, our default architecture decision remains vector or hybrid retrieval unless an evaluation demonstrates a material gain on global, multi-document questions. That is a deployment heuristic, not a measured universal threshold. On a small corpus, long-context generation may also be cheaper and simpler than maintaining a graph.

In our architecture review, we identified dual-level retrieval and incremental insertion as relevant capabilities, but established no transferable break-even corpus size. When we inspected the older LightRAGTest comparison harness, we could verify CLI and model setup, not numerical results. Its single-file literary corpus, older versions, laptop hardware, and changed chat-model tier prevent us from treating it as a current production budget.

Our Final Verdict: When to Deploy, When to Skip

LightRAG is the more practical starting point when we need graph-assisted retrieval without committing immediately to full community-report generation. Its dual-level design maps cleanly to entity-specific and thematic questions, and its incremental architecture is better aligned with frequently changing knowledge bases.

Microsoft GraphRAG remains the stronger conceptual fit when global corpus synthesis is the core product feature and we can afford a substantial preprocessing pipeline. Its global search is not merely vector search with graph labels; the community-report hierarchy is the feature and the expense.

LazyGraphRAG is strategically interesting because it moves that expense from ingestion to query time. We would not put its headline ratios into a financial model until we can run the exact implementation, model mix, relevance-test budget, and corpus ourselves. The Microsoft research description is evidence for the design, not a quote for our cloud bill.

Deploy LightRAG if:

  • Entity relationships materially affect answer quality.
  • The corpus changes often enough that full rebuilds are unacceptable.
  • We can pin package versions, prompts, chunking, and embedding dimensions.
  • We are prepared to move beyond the default local stores.
  • We can meter extraction and query calls at the provider boundary.
  • Local and global queries are evaluated separately.

Deploy full GraphRAG if:

  • Corpus-wide synthesis is a primary user workflow.
  • Community reports demonstrably improve answer completeness.
  • The index changes slowly relative to query volume.
  • We can absorb and monitor the up-front summarization bill.
  • We need the richer local, global, and DRIFT search portfolio.

Hold off or avoid both if:

  • Most questions are direct “who,” “what,” “when,” or “where” lookups.
  • The corpus contains only a few dozen short documents.
  • Source documents change continuously.
  • We cannot build a citation-based quality set.
  • A vector baseline has not been measured first.
  • The business case depends on benchmark numbers from different versions or corpora.

Our blunt conclusion is that LightRAG is easier to justify operationally than full Microsoft GraphRAG, but neither earns deployment merely by producing an attractive graph visualization. The graph has to improve the questions customers actually ask.

Before approving either system, we would run a vector baseline, freeze a representative corpus, instrument every model call, edit one existing document, and calculate break-even using our own traffic forecast. If that experiment is difficult to design internally, contact our architecture team or review our implementation work under AI infrastructure services. The expensive mistake is not choosing the “wrong” graph framework. It is committing to graph indexing without knowing which query failures it is supposed to fix.

Top comments (0)