How Cursor Tab learns from your codebase (and why it sometimes doesn't)
Published 2026-05-11 by Owner
Cursor Tab is the grey-text inline completion that appears as you type and disappears the moment you press Tab to accept it. It looks simple — a fancy autocomplete — but the suggestions are grounded in something more substantial than the current file. Tab has an index of your entire repository, and it uses that index to predict what code fits your codebase specifically rather than what code looks statistically common across GitHub.
That grounding is what makes Tab useful. It’s also what makes it confusing when it goes wrong.
Most Tab frustration comes from a mismatch between what the index knows and what the developer expects it to know. Understanding the mechanics — what’s in the index, what’s excluded, when it updates — turns “Tab is useless” into a concrete debugging problem with concrete fixes.
The same feature that makes Tab powerful (codebase grounding) is the source of confusion when the grounding lags behind reality. The model itself hasn’t changed; what changed is what evidence it has access to.
This reframe — from “Tab is wrong” to “Tab is retrieving the wrong evidence” — is the most useful mental shift for getting consistent value out of it.
What the repo index contains, and what it skips
When Cursor opens a workspace, it indexes the project in the background. That index is not a raw file dump — it contains several layers of information that shape what Tab suggests:
File content. Full text of source files, stored in a structure that allows fast similarity lookup. Tab searches the index for code patterns similar to what you’re currently writing.
AST-level structure. For supported languages, the index includes parsed structure — function signatures, type definitions, class hierarchies. This is why Tab can complete a method name with the correct signature even if the definition is in a file you haven’t opened today.
Recent-edit weighting. Files you’ve edited in the current session receive higher weight in retrieval. The model prioritizes evidence of where the codebase is going, not just where it has been. A file touched five minutes ago outweighs a file touched two weeks ago, even if the older file is nominally more central to the codebase.
Proximity in the file tree. Files in the same directory as the current file get extra weight. If you’re editing src/features/auth/login.ts, files in src/features/auth/ surface more readily than files in src/utils/.
Import graph signals. The modules imported by the current file are tracked. If the current file imports UserSchema from @/schemas/user, the schema file gets a relevance boost in retrieval. This makes Tab especially good at completing code that uses types or functions already imported in the same file.
Tab draws on a retrieval step that runs before each completion. The things most likely to show up in that retrieval window:
- The current file — always in context
- Open editor tabs — files open in the editor influence the retrieval query directly
- Files edited recently in this session — carry elevated weight
- Files in adjacent directories — proximity matters
- Imported modules — if the current file imports from
@/lib/validators, that file is likely indexed and retrievable
Concretely: if you renamed a utility function yesterday and have that file open, Tab will suggest the new name. If the file is closed and you haven’t touched it in this session, Tab might still suggest the old name — it’s retrieving from the index snapshot, not the live file.
This matters more than it initially seems. A long session where you were reading old code in one tab cluster and writing new code in another will have a split retrieval pool. The old-code tabs contribute to retrieval alongside the new-code tabs. Understanding this explains why closing a batch of reference tabs can immediately improve suggestion quality — it’s not superstition, it’s removing noise from the retrieval query.
Several things are outside Tab’s retrieval reach entirely:
Gitignored files. The .gitignore list is respected during indexing. Environment configs, build artifacts, and anything in node_modules/ don’t appear in the index. Tab will never suggest a pattern from a file that’s gitignored.
Files outside the open workspace. Index retrieval doesn’t cross Cursor windows. Patterns from a sibling project aren’t visible even if both windows are open side by side.
Content on unmerged branches. The index reflects files on disk in your current checkout. Stale patterns on branches you checked out weeks ago don’t persist after switching away.
Very large binary or generated files. Files above a certain size threshold get skipped during indexing. Auto-generated API clients or large JSON fixtures may be omitted even if not gitignored.
A concrete example of this blind spot: suppose a project uses a code generator that outputs TypeScript interfaces from an OpenAPI spec. The generated file sits at src/generated/api-types.ts and is gitignored to avoid committing machine output. Tab will never suggest those type names. If the workflow requires using those types, they need to either be un-gitignored or manually re-exported from a non-ignored barrel file that Tab can see.
The index is also probabilistic in what it surfaces. Not every indexed file appears in every retrieval — the system selects the most relevant subset. High relevance signals (file is open, edited recently, shares imports with the current file) increase the odds but don’t guarantee inclusion.
Diagnosing “Tab is suggesting the old pattern”
The most common complaint about Tab in maturing codebases: it keeps suggesting a pattern that was deprecated two sprints ago. The new pattern is already used in twenty files. Yet Tab still reaches for the old one.
This is almost always an index freshness problem, not a model quality problem. The diagnostic:
-
Check which files you have open. If the files open in your editor tabs are old files that haven’t been updated to the new pattern, those files are biasing retrieval toward the deprecated form. Close the stale tabs.
-
Check whether the canonical new-pattern file is open. Tab weighs open files heavily. If you want it to suggest the new
useDataFetcherhook instead of the oldfetchWithCallback, open the file whereuseDataFetcheris defined. Retrieval will surface it. -
Check how recently you edited the relevant files. Recent edits get weighted up. If the new pattern was introduced by someone else on a different machine, your local recent-edit history doesn’t include those files. Open them, read through them once — that’s often enough to shift retrieval.
-
Check the directory. If the deprecated pattern is common in files near your cursor location and the new pattern lives in a different part of the tree, proximity weighting may be working against you. Moving toward the new-pattern directory (or opening a file from it) shifts the balance.
# Checklist when Tab keeps suggesting wrong patterns
# 1. Close editor tabs that contain the old pattern
# 2. Open the file that best exemplifies the new pattern
# 3. Edit at least one line in a file that uses the new pattern
# (even a no-op comment edit) — this raises it in recent-edit weight
# 4. Position the cursor in a directory where the new pattern is common
What triggers a re-index of the full workspace: a branch switch (files that differ between branches get re-indexed), a settings change that affects indexing scope, major directory restructuring, or the first open after a long absence. The status bar shows an indexing indicator when a full re-index is running. On a large monorepo, this can take several minutes — Tab is still functional during that window but uses the prior index state.
What does NOT trigger a re-index: saving a single file during normal editing. The index updates incrementally on saves, but the increment may lag by a few seconds. This is normal and not worth worrying about.
One common post-rebase pitfall: after a rebase that rewrites many commits, the files on disk look the same but the git history has changed. Cursor doesn’t re-index based on history changes — only on file content changes. So a rebase that produces identical file content won’t trigger re-indexing. If the rebase involved cherry-picks or conflict resolution that changed file content, those files will get updated in the incremental index on the next save cycle.
Tuning Tab when it feels wrong
Beyond diagnosis, there are a few active interventions that consistently help:
Open the canonical file as a hint. Retrieval weights open files. If Tab is confused about which validation library to use, opening src/lib/validators.ts is a more direct hint than hoping the index finds it on its own.
Close tabs from old files. A tab accumulation problem is common in long sessions. Tabs opened early in the day (when the codebase was in a different state, or when reading old code) keep those files in retrieval weight. A periodic cleanup — closing anything not actively needed — has a measurable effect on completion relevance.
Edit a representative file. If Tab keeps missing a pattern introduced in one specific file, edit something small in that file (add a comment, fix whitespace) to inject it into recent-edit history. Slightly cynical, but it works.
Restart Cursor after a major environment change. Pulling a branch with hundreds of changed files, applying a large patch, or running a migration script that touches the whole schema layer can leave the incremental index in an inconsistent state. Restarting Cursor forces a clean index rebuild. This is a last resort, not a first step — but it resolves situations where the above steps don’t help.
Avoid keeping deprecated files open. Legacy code kept open as reference pulls the retrieval window backward. If reading old code to understand how something used to work, close it when done.
Use a .cursorignore file for large generated output. Similar to .gitignore, Cursor respects a .cursorignore file that explicitly excludes directories from indexing. If the repo has a large __generated__/ folder that changes on every build, excluding it removes noise from the retrieval pool.
# .cursorignore example
__generated__/
*.pb.go
dist/
.next/cache/
coverage/
This file is separate from .gitignore, so it can be tuned independently of what gets committed. Over-indexing large generated or vendored directories is a common cause of Tab suggestions that feel “generic” — the generated code dilutes the retrieval pool with patterns that may not match the project’s handwritten conventions.
Check the Cursor indexing status before concluding Tab is broken. The bottom status bar shows an active indexer when a full re-index is running. On repos with hundreds of thousands of lines, the initial index after a major branch switch can take three to five minutes. Suggestions during this window use the prior state. Seeing wrong suggestions for a few minutes after a big merge is expected behavior, not a bug.
For monorepos, consider workspace scoping. Cursor indexes the entire open workspace. If a monorepo has twelve packages and the current work touches only two, opening the workspace root means Tab’s retrieval pool includes all twelve packages. Opening only the relevant package subdirectory as the workspace root narrows the pool and often improves suggestion relevance for that package’s patterns.
The earned insight
The thing that took time to understand: Cursor Tab’s usefulness is partially a function of session hygiene. The completions are only as current as the retrieval window, and the retrieval window reflects what you have open and what you’ve touched recently.
A well-maintained session — close what you don’t need, open what you do, edit forward rather than reading backward — produces better Tab suggestions than any settings change. The model is the same either way; the difference is what evidence it retrieves to ground the completion.
This is different from how most developers think about autocomplete. Traditional autocomplete is purely syntactic — it sees the current file and produces a lexically plausible continuation. Tab is retrieval-augmented — it searches the index and produces a continuation grounded in your codebase’s actual patterns. That’s the capability. The corollary is that the quality of the index, and what gets prioritized in retrieval, shapes every suggestion that appears.
The implication for team workflows: if Tab feels unreliable for a new team member, the most likely explanation is not that Tab is broken for them — it’s that they haven’t built up the recent-edit history that weights retrieval toward current patterns. A few hours of editing across the active parts of the codebase rebuilds that signal. The first day on a repo is always Tab’s worst day.
There’s also an argument for using Cursor Rules (.cursor/rules/) alongside good index hygiene. Rules tell the model what conventions to prefer in completions; the index provides evidence of those conventions in practice. Neither substitutes for the other. Rules are instructions; the index is grounding. When both point the same direction — rules say “use Zod for validation” and the index contains twenty Zod schemas — Tab’s suggestions are reliable. When they diverge (rules say Zod, but the index contains an older Joi migration that’s still half-complete), the index often wins. Finishing the migration is the fix, not writing a stronger rule.