Quick Start
This walkthrough takes you from zero to searching your codebase in under a minute.
1. Index your project
Section titled “1. Index your project”From your project root:
rfx indexReflex walks your source tree, extracts trigrams for every file, and builds a memory-mapped index. It covers the same files ripgrep searches by default: every non-binary file that is not gitignored and not under a dot-directory. On the Reflex repository itself (298 files), a full index takes about half a second; a 27,448-file Kubernetes checkout indexes in 7.7 seconds on a 16-core machine.
Indexing complete! Files indexed: 298 Cache size: 10.68 MB Index/corpus ratio: 1.3x (trigrams.bin 5.94 MB, content.bin 4.42 MB) Last updated: 2026-09-23T18:48:45+00:00 Breakdown: 298 new, 0 modified, 0 unchanged Text: 67 files, Lock: 1, Generated: 0 (lock and generated are excluded from searches unless asked for) Coverage: ripgrep defaults — not gitignored, not binary, not under a dot-directory ([index] hidden = true to include them)
Files by language: Language Files Lines ---------- ----- ------- Rust 179 100331 Text 67 25661 Python 18 4810 TypeScript 11 834 ...
Starting background symbol indexing... Symbols will be cached for faster queries Check status with: rfx index statusFiles without a symbol parser — docs, config, and anything else that isn’t code — are indexed as Text and are fully searchable. Lock files and generated files are indexed too, but left out of results unless you ask for them.
The index is incremental — subsequent runs only reprocess changed files, detected by file content (size, modification time, and blake3 hash):
Breakdown: 0 new, 1 modified, 297 unchangedAfter indexing, a background pass parses every file once and caches its symbols, so --symbols queries are fast. Symbol queries still work before it finishes; check its progress with rfx index status.
2. Search for text
Section titled “2. Search for text”rfx query "resolve_thread_count"This performs a full-text search across every indexed file. Results are grouped by file, with the line number and matching line:
📁 src/indexer.rs (1 match) 504 let num_threads = crate::models::resolve_thread_count(self.config.parallel_threads, 32);
📁 src/models.rs (1 match) 635 pub fn resolve_thread_count(configured: usize, auto_cap: usize) -> usize {
📁 src/query/open_index.rs (1 match) 161 crate::models::resolve_thread_count(config.parallel_threads, QUERY_AUTO_THREAD_CAP);
Found 3 results in 9msBy default a pattern matches whole identifiers: thread_coun does not match resolve_thread_count. When a search comes back empty, Reflex tells you if a substring search would have found something:
Hint: 0 whole-identifier matches; 6 substring matches — pass contains:true (--contains on the CLI) to see them. Reflex matches whole identifiers by default, so "thread_coun" does not match longer names that merely contain it.No results found (searched in 7ms).A few flags change how matching works:
--contains— match substrings (Erroralso matchesNetworkError)-i/--ignore-case— match regardless of case, likerg -i--include-locks/--include-generated— also search lock files (Cargo.lock,package-lock.json) and generated files (*.pb.go,*.min.js)
By default a query returns the first 100 results (change it with --limit, page with --offset). When there are more, the footer shows the total — or an estimate when counting every match would slow the search down:
Found 100 results (~1476 total, estimated) in 8msUse --limit/--offset to paginate, or --count for the exact total3. Filter by symbols
Section titled “3. Filter by symbols”Add --symbols (or -s) to restrict results to symbol definitions — functions, classes, structs, types:
rfx query "resolve_thread_count" --symbols 📁 src/models.rs (1 match) 635 [fn] resolve_thread_count pub fn resolve_thread_count(configured: usize, auto_cap: usize) -> usize { if configured != 0 {…
Found 1 result in 7msUse --kind to narrow further (it implies --symbols):
rfx query "IndexConfig" --kind struct4. Filter by language
Section titled “4. Filter by language”rfx query "import" --lang typescriptUse --lang text to search only non-code files (docs, config), or --lang lock / --lang generated to search only lock or generated files.
5. Get JSON output
Section titled “5. Get JSON output”For scripts and AI pipelines, use --json:
rfx query "resolve_thread_count" --symbols --json --pretty{ "status": "fresh", "can_trust_results": true, "pagination": { "total": 1, "count": 1, "offset": 0, "limit": 100, "has_more": false, "total_is_exact": true }, "results": [ { "path": "src/models.rs", "language": "rust", "matches": [ { "kind": "Function", "symbol": "resolve_thread_count", "span": { "start_line": 635, "end_line": 643 }, "preview": "pub fn resolve_thread_count(configured: usize, auto_cap: usize) -> usize {\n if configured != 0 {…" } ] } ]}Every response reports whether the index matches your working tree: status is "fresh" or "stale". When it is stale, can_trust_results is false and a warning object explains why and lists the changed files — re-run rfx index to refresh:
{ "status": "stale", "can_trust_results": false, "warning": { "reason": "Files changed since the index was built (1 modified) — these results may not reflect them", "action_required": "index_project", "files_modified": [ "src/lib.rs" ], "changed_count": 1, ... }, ...}When the total is estimated, pagination.total is null, total_is_exact is false, and approx_total holds the estimate.
6. Interactive mode
Section titled “6. Interactive mode”Launch the TUI for interactive search:
rfx queryType a pattern and press Enter to search, move through results with ↑/↓, press Enter on a result to preview the file, and press o to open it in your editor. See the Interactive Mode guide for keybindings and editor integration.
Next steps
Section titled “Next steps”- Configuration — customize index settings, file limits, and performance tuning
- Full-Text Search — understand trigram search in depth
- Symbol Search — filter by functions, classes, and more
- AI Integration — connect Reflex to AI coding assistants via MCP