Denis Baciu canonical archive · est. 2026

Writing

What Graph RAG Changes About Code Migration Retrieval

source: linkedinoriginal ↗
published: 2026-09-19 · status: canonical · expanded from the original post
What Graph RAG Changes About Code Migration Retrieval

Most retrieval-augmented generation (RAG) pipelines I see for code treat a repository like a collection of documents. They split files into chunks, embed each chunk, and retrieve by vector similarity. For question answering over prose, that is a reasonable starting point. For enterprise code migration, it misses the structure that determines what must actually change when a module moves or an API is updated.

A call graph is not a paragraph. Dependencies are not synonyms. Vector search may surface methods that use the same words but sit in unrelated execution paths. Two functions can mention payment, validation, or order processing and have no relationship at runtime. The retrieval looks plausible and is still wrong.

Enterprise code migration often means decomposing a monolith or modernizing an old stack. You need to know not just which files are related, but which functions call each other, which modules own which responsibilities, and which dependencies cross boundaries. That is structural information, and it is exactly what a graph representation captures.

The paper “Beyond Vector Similarity: Hierarchical Context-Aware Graph RAG vs Standard RAG in Enterprise Code Migration” compares standard RAG with a graph-based alternative. The graph version builds context from how the code is actually structured: call hierarchy, module boundaries, dependency links. Retrieval then follows real code relationships rather than lexical overlap. In plain English, it is the difference between finding “code that mentions payment” and finding “the exact functions that must change and the things they depend on when you alter the payment flow.”

Standard RAG versus graph RAG for code migration.
Fig 1. Standard RAG versus graph RAG for code migration.

Richer context costs something. The authors report trade-offs in cyclomatic complexity and docstring preservation. But they also measure much lower API hallucination rates and better dependency resolution. When you are moving a monolith to microservices or modernizing a legacy stack, that second metric is the one that matters most. Hallucinated APIs and missed dependencies turn a migration plan into a debugging exercise. A lower API hallucination rate means the generated migration code is less likely to invent endpoints or signatures that do not exist; better dependency resolution means the plan accounts for the transitive callers and callees that actually have to be updated.

Vector similarity alone is not wrong; it is incomplete for code. It finds similar language. It does not find the subgraph of functions that must change together. That distinction is easy to overlook when the demos are small enough that semantic search happens to surface the right file. Large monoliths have repeated terms across modules, legacy naming conventions, and duplicate utilities that confuse a pure embedding approach.

If you work on RAG tools for code migration, the paper is worth a close read. The takeaway I keep returning to is that code retrieval needs to respect structure, not just text. Once retrieval follows call and dependency edges, the rest of the pipeline—generation, planning, diff review—becomes a lot more grounded.