Skip to content

Symbol Search

Symbol search combines Reflex’s full-text trigram search with Tree-sitter parsing to filter results down to symbol definitions — functions, classes, structs, interfaces, and more.

Reflex uses a two-phase approach:

  1. Trigram search finds the files containing the query text (fast, milliseconds)
  2. Symbol lookup reads each candidate file’s symbols from the symbol cache and keeps the definitions that match

The symbol cache is filled by a background symbol pass: after rfx index finishes the trigram index, it starts a detached process that parses every file once with Tree-sitter and stores the symbols (zstd-compressed) in .reflex/meta.db. You can search as soon as rfx index returns; any file the pass hasn’t reached yet — or that changed since — is parsed at query time and added to the cache.

Starting background symbol indexing...
Symbols will be cached for faster queries
Check status with: rfx index status

rfx index status shows the pass’s progress (State: Completed, files processed, parsed and failed).

Add --symbols (or -s) to any query:

Terminal window
rfx query "IndexConfig" --symbols
src/models.rs (1 match)
522 [struct] IndexConfig
pub struct IndexConfig {
/// Languages to include (empty = all supported)
pub languages:…
Found 1 result in 15ms

Without --symbols, this query returns 282 results in the Reflex repo — every use, import, comment and doc mention of IndexConfig. With it, only the definition appears.

Symbol names are matched as whole names by default. Add --contains for substring matching on symbol names, or --exact to require an exact name (the two can’t be combined). Add --expand to show the full definition body instead of a preview.

Use --kind (or -k) to restrict to a specific symbol type. --kind implies --symbols, so you don’t need both:

Terminal window
# Only functions (also includes methods)
rfx query "hash_content" --kind function
# Only structs whose name contains "Config"
rfx query "Config" --kind struct --contains
# Only interfaces (TypeScript, Go, Java, …)
rfx query "User" --kind interface

Searching for a language keyword lists every symbol of that kind — for example, every Rust trait:

Terminal window
rfx query "trait" --kind trait --lang rust
KindDescription
functionFunctions (--kind function also returns methods)
methodMethods
classClasses
structStructs
enumEnums
interfaceInterfaces
traitTraits (Rust, PHP)
typeType aliases and type definitions
constantConstants
variableVariables, let bindings
moduleModules (Rust, Ruby)
namespaceNamespaces (C++, C#, PHP)
macroMacros (Rust, C)
propertyProperties (C#, Ruby)
eventEvents (C#)
attributeAttributes and annotations
importImports
exportExports

--kind accepts all 18 kinds, but no bundled parser currently emits import or export symbols — use dependency analysis to explore imports. Symbol kinds vary by language — see Supported Languages for what each language extracts. Text, lock and generated files have no symbols.

In text output each result carries a short badge: [fn], [method], [struct], [const], [var], [mod], and so on.

Symbol search composes with all other query filters:

Terminal window
# Symbols in a specific language
rfx query "parse" --symbols --lang rust
# Symbols in files whose path contains src/interactive/
rfx query "InputField" --symbols --file src/interactive/
# Symbols under a directory (gitignore-style glob)
rfx query "search" --kind function --glob "src/query/**"
# JSON output for tooling
rfx query "IndexConfig" --kind struct --json

In JSON, each symbol match carries kind (e.g. "Struct"), symbol (the name) and a span covering the whole definition:

{
"kind": "Struct",
"symbol": "IndexConfig",
"span": { "start_line": 522, "end_line": 572 },
"preview": "pub struct IndexConfig {\n /// Languages to include (empty = all supported)\n pub languages:…"
}

Symbol search only looks at files that pass the trigram filter, and for those it normally decodes cached symbols rather than parsing. Queries like the ones above take 6–25 ms on the Reflex repository.

On large codebases, symbol search is often faster in practice because it returns fewer results, reducing output formatting time. Queries that would have to parse more than 5,000 candidate files are refused unless you pass --force — narrow them with --lang, --file or --glob instead.