Stephan Schmidt - June 27, 2026
Grep or LSP in Claude Code? You Want Both
Claude Code searches your code with plain text by default. Here is when to leave it that way, and when to turn on LSP.
TL;DR: Run LSP for your main stack so Claude gets instant, symbol-accurate definitions and references (and catches broken call sites right after an edit), but keep grep for everything that isn't code - logs, configs, comments, string literals, feature flags - and for whole-tree sweeps where text search wins. The trap is silent fallback: a misconfigured language server sends Claude back to grepping for refactors, burning tokens and context, so verify which one is actually running by asking it to "go to definition" and watching for the LSP label.
Turn on LSP in Claude Code and don’t throw grep (or ripgrep!) away. I wrote a whole post on how to set up LSP in Claude Code and why semantic lookups beat grepping around in the dark, and I stand by every word of it, but somewhere between writing that and using it for a few weeks I watched a few people rip grep out of their head as “the dumb thing Claude used to do” - and that’s wrong. Claude Code reaches for plain text search before anything else, with no index built and nothing embedded, and that is a deliberate choice, and for most of what Claude does all day it is the right one.
So which one for which job?
What grep actually does for Claude
Out of the box Claude does not understand your code. It searches text. Regex over files, it never builds an index ahead of time and never embeds anything, no semantic model of your project. The system prompt even tells it to reach for ripgrep first before anything else, and for years the one-line description of how Claude finds things was “it shells out to rg”.
The reason it’s text search and not something cleverer is that text search has no setup, matches exactly what you typed, works on any tree in any language whether or not a language server exists for it, and respects your .gitignore without being told - and Claude is very well trained on common tools like grep. You point Claude at a fresh repo in some language you’ve never configured and it can still find things. Claude then papers over the dumbness of plain search with agentic exploration - it greps, reads a file, greps again, follows a hunch, reads three more - which works, and which also reads a lot of your codebase to answer one question.
And it uses ripgrep for the fastest search.
Is it still ripgrep? Maybe not
But in 2026 “Claude Code uses ripgrep” stopped being reliably true. Somewhere around v2.1.116/117 the built-in search swapped under the hood from ripgrep to ugrep.
What the language server gives Claude
LSP (Language Server Protocol) is the other thing to read and find things, and it’s a different kind of thing entirely. It’s the same Language Server Protocol every editor runs to jump to a definition - depending on the programming language wired to gopls, rust-analyzer, pyright, typescript-language-server - and gives Claude semantic operations: go to definition, find all references, hover types, list symbols, and diagnostics after every edit. Claude changes a function, the language server immediately tells it the three call sites that no longer compile, and it fixes them in the same turn instead of finding out two steps later when something blows up. That’s the kind of thing that made Claude pick up a new superpower with a real IDE intelligence sitting inside the agent.
Installation was and is difficult. Plugins for LSP in Claude were inert for some people on day one, some language servers are memory pigs, and you’ll occasionally restart Claude to get it talking to the server again. (The full setup, language by language, is in the LSP setup post.)
When to use grep as the right tool
Grep is not the fallback if LSP does not work. There’s a whole class of work where it’s the only tool, and it’s a bigger class than people think.
Anything that isn’t code: log lines, comments, a string literal somehwere, a config key, a TODO, a feature flag’s name scattered across YAML and Go and the frontend. LSP doesn’t work with that - it deals in symbols - and grep finds it. Breadth is the other place: when you want to sweep an entire tree and see every spot a word appears, grep is built to do exactly that in one pass, which is something a symbol graph usually can’t (but other symbolic tools beside LSP are better here). Also: languages where no server exists, huge monorepos where pyright or rust-analyzer crawl or crash (this is exactly when you disable the plugin and fall back to grep), and the fact that it honours your .gitignore (you think gitignore hides your files and then the agent grabs something it shouldn’t), stays predictable, and needs nothing set up at all.
Where grep isn’t the best tool
“Where is this defined?” With LSP it’s an instant file and line. With grep Claude greps the name, gets back the definition plus every call plus a few matches inside comments and strings, and has to dig the real one out of the pile. “Who calls this?” is the one that matters before a refactor, and it’s the one grep gets wrong - a text search for a method name misses references, catches unrelated same-named things, and leaves some call sites out without a word, so Claude renames a function, thinks it got them all, and breaks the three it never saw. A symbol-aware rename doesn’t have that failure mode. TOKENS! TOKENS! TOKENS!
PLUS a semantic lookup comes back in under fifty milliseconds if the data is in memory; the grep-and-read-and-grep-again dance to answer the same “where does this live” question can run three to eight seconds and, in one case I watched, had Claude read something like forty percent of the codebase into context just to refactor one function. It’s slow for more complicated questions and fills the context window - which then limits how much real work the agent does in one go - with files it only opened to search - and again: TOKENS, TOKENS, TOKENS (with a filled context window).
What about other tools? Serena and Codegraph?
LSP in Claude is the language server talking straight to the agent, one question at a time: where is this defined, who calls it, what type is this. LSP mainly come from IDEs where they help the IDE to work with a programming language without the IDE needing to support all languages - several LSPs come from the language committers.
There are other tools that do something like this too. Especially two tools sit a layer above that and go after the same thing this whole post is about - saving tokens.
serena is an MCP server you point an agent at. Under the hood it runs the same language servers, over forty languages, and hands the agent symbol-level tools: find a symbol, list references, pull a file outline, walk a type hierarchy. Where it goes past plain LSP is the editing - rename across files, replace the body of a function, insert before or after a symbol - so a refactor that would be eight or ten read-then-search-then-replace steps turns into one call. Fewer steps, fewer tokens and less files dragged into context to do the edit (again saving tokens).
codegraph takes a different road. It doesn’t ask a language server live. It parses your code with tree-sitter ahead of time, pulls out the symbols and the edges between them - calls, imports, inheritance - and stores the graph in a local SQLite database that it keeps in sync as files change. The agent gets one tool, codegraph_explore, and one call hands back the entry points, the related symbols and the snippets around them. No grep, read, and grep again. The numbers the developers post go at the token problem head on: around 58% fewer tool calls, file reads down to near zero (because they are indexed), and on some repos the agent uses 64% fewer tokens.
LSPs were written for humans and IDEs.
Those new tools are written for AIs.
So which one?
Both are useful, but you want to know which one is running. Wire up the language server for your main stack, leave grep doing what grep is good at. Be careful that Claude doesn’t fall back to grep because LSP is misconfigured. It also easily falls back to grep if something in LSP doesn’t work as intended, it kind of “feels” that it can get there with grep either way - one LSP error and it might just grep again.
There’s a thirty-second way to tell which one Claude is reaching for. Ask it to “go to definition” of something. If you get a file and a line instantly and see an LSP label in the output, the language server is wired in. If it says “let me search through the codebase” and you watch it grep, it isn’t - and you’ve got the setup to go fix.
Me personally, for decades I use plain grep with find, e.g. find . | grep <file> - never learned the in and outs of grep, learned about rg far too late. Not about LSP vs. Grep,
but Claude is really good at knowing all the bells and whisles of a tool. SO I’ll keep grepping. I just don’t make Claude do it for the jobs where it’s the wrong tool.
PS: I use Codegraph.
About me: Hey, I'm Stephan, I help CTOs with Coaching, with 40+ years of software development and 25+ years of engineering management experience. I've coached and mentored 100+ CTOs and founders. I've founded 3 startups. 1 nice exit. I help CTOs and engineering leaders grow, scale their teams, gain clarity, lead with confidence and navigate the challenges of fast-growing companies.
Most of the CTOs I coach didn't know CTO coaching was a thing until they were already drowning. It is a thing - here's what it is.