Mental-model reset for Salsa, the incremental computation framework for Rust. Use when building or reviewing Salsa databases, tracked functions, input/ tracked/interned structs, query pipelines, accumulators, cancellation, durability, LSP integration, memory management, cycles, or production Salsa architecture. Triggers on #[salsa::db], #[salsa::input], #[salsa::tracked], #[salsa::interned], #[salsa::accumulator], salsa::Storage, memoization, revisions, backdating, red-green algorithm, WillExecute, DidValidateMemoizedValue, Cancelled, returns(ref), no_eq, lru, cycle_fn, cycle_result, durability, or salsa::Event.
90
86%
Does it follow best practices?
Impact
95%
1.66xAverage score across 3 eval scenarios
Passed
No known issues
Salsa is a framework for incremental recomputation. You define inputs and pure functions over them. Salsa memoizes every function call. When inputs change, it re-executes only the functions whose dependencies actually changed — skipping everything else.
Salsa powers rust-analyzer (Rust IDE), ty (Python type checker), and Cairo, all of which need sub-second response times on large codebases after small edits.
Salsa Database
┌─────────────────────────────────────┐
External world │ │
(editor, CLI, │ Inputs ──→ Tracked Fns ──→ Output │
filesystem) │ │ │ │
│ │ └── memoized ┘ │
│ │ dependencies tracked automatically│
▼ └─────────────────────────────────────┘
Mutate inputs │
(new revision) ▼
Only re-run what changedThe core loop:
let db = MyDatabase::default();
// 1. Create inputs
let file = SourceFile::new(&db, "fn main() {}".into(), path);
// 2. Compute (Salsa memoizes everything)
let result = analyze(&db, file);
// 3. Mutate an input (starts a new "revision")
file.set_text(&mut db).to("fn main() { 42 }".into());
// 4. Re-compute — Salsa reuses what it can
let result = analyze(&db, file); // Only re-runs what depends on textA struct with #[salsa::db] that stores all cached data. It's the single source of truth — every Salsa operation takes a &db or &mut db.
#[salsa::db]
#[derive(Default, Clone)]
pub struct Database {
storage: salsa::Storage<Self>,
}
#[salsa::db]
impl salsa::Database for Database {}→ Deep dive: database-architecture.md for layered traits, test vs production, and side tables.
External data entering the system. The only mutable Salsa structs. Just newtypes around integer IDs (Copy, no lifetime).
#[salsa::input]
pub struct SourceFile {
#[returns(ref)]
pub text: String,
pub path: PathBuf,
}Pure functions whose results are memoized. Salsa records which inputs/fields each call reads. On re-execution, it checks if those dependencies changed.
#[salsa::tracked]
fn parse(db: &dyn Db, file: SourceFile) -> Ast<'_> {
let text = file.text(db); // dependency recorded
// ... parse ...
Ast::new(db, statements)
}→ Deep dive: query-pipeline.md for return modes, LRU, no_eq, specify, and granularity.
Created inside tracked functions. Have per-field change tracking. Carry a 'db lifetime.
#[salsa::tracked]
pub struct Function<'db> {
#[id]
pub name: Word<'db>, // used for cross-revision matching
#[tracked]
#[returns(ref)]
pub body: Expression<'db>, // per-field tracking
}Same data → same integer ID. Used for identifiers, type representations, module paths. Carry a 'db lifetime.
#[salsa::interned]
pub struct Word<'db> {
#[returns(ref)]
pub text: String,
}→ Deep dive: struct-selection.md for the decision framework, including ty's "no tracked structs" and rust-analyzer's "intern every definition" styles.
Report diagnostics from tracked functions without affecting the return value.
#[salsa::accumulator]
pub struct Diagnostics(Diagnostic);
// Inside a tracked function:
Diagnostics::push(db, Diagnostic { message: "type error".into(), .. });→ Deep dive: accumulators.md.
Every input mutation increments a revision counter. When you call a tracked function, Salsa checks its dependencies since the last cached result. If they changed, it re-executes; if the new result equals the old one (backdating), it stops propagation.
Inputs can be tagged with LOW, MEDIUM, or HIGH durability. When only LOW-durability inputs change, Salsa skips validating stable subgraphs.
→ Deep dive: durability.md.
| I want to... | Read |
|---|---|
| Choose between input, tracked, and interned | struct-selection.md |
| Design my tracked functions and query graph | query-pipeline.md |
| Structure my database with layered traits | database-architecture.md |
| Handle recursive/cyclic queries | cycle-handling.md |
| Support cancellation in an LSP or CLI | cancellation.md |
| Optimize with durability levels | durability.md |
| Test that incremental reuse actually works | incremental-testing.md |
Control memory with LRU and no_eq | memory-management.md |
| Build an LSP server backed by Salsa | lsp-integration.md |
| Report diagnostics via accumulators | accumulators.md |
| Move from prototype to production scale | production-patterns.md |
| Access low-level plumbing and "Level 4" patterns | advanced-plumbing.md |
no_eq: Skip equality comparison on result — always propagate changes.CloneableDatabase.The hardest part of Salsa is the design decisions about granularity, identity, and what to track. django-language-server and BAML are the best starting points for learning. stc [Legacy API] is the best example of wrapping an existing non-Salsa library with minimal Salsa code. Mun [Legacy API] is the best example of extending Salsa queries all the way to machine code generation and hot reloading.
examples/calc/, examples/lazy-input/)crates/ty_* and crates/ruff_db in https://github.com/astral-sh/ruff40067f1
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.