Rider’s Solution‑Wide Analysis: Powerful Cross‑Project Refactoring with Real‑World Trade‑offs
Rider’s persistent semantic index enables instant cross‑project refactorings and solution‑wide inspections, but large solutions need heap tuning, selective analysis scoping, and shared cleanup profiles to stay responsive.
09 Aug 2026, 08:35 UTC

The problem: large .NET solutions feel sluggish and refactorings miss references
When a solution grows past a few dozen projects, developers often notice two things: the IDE takes minutes to become responsive after opening, and a simple rename of a public interface leaves stale references in other projects, XAML files, or even .csproj version attributes. JetBrains Rider addresses both with a persistent semantic index (PSI) that powers solution‑wide inspections and refactorings, but the feature set comes with memory and configuration costs that need deliberate tuning.
How the persistent semantic index works
Rider builds a PSI for every project in the solution at startup. The index stores resolved symbols, type information, and call‑graph edges, enabling instant Find Usages, Rename, and Navigate To across project boundaries without a full rebuild. Because the PSI is persisted, incremental updates keep it current as you edit, and background indexing prevents the UI from blocking.
- Indexes C#, VB.NET, F#, Razor, XAML, and project files.
- Operates on the semantic model, not raw text, so refactorings update generated code (e.g.,
.g.cs) and metadata files automatically. - Can be disabled per‑project via
.editorconfig(dotnet_analyze_scope = project) to speed up indexing at the cost of losing cross‑project diagnostics.
Solution‑wide inspections and shared Code Cleanup
With solution‑wide analysis enabled (default), Rider runs over 2,000 inspections — nullability, serialization safety, API misuse, naming conventions — and aggregates results in the Inspection Results tool window, grouped by severity and file. A single Code Cleanup profile can apply formatting, remove redundant using directives, convert loops to LINQ, and enforce naming rules in one pass. Profiles are stored in .dotsettings layers that can be checked into source control, so the whole team shares the same cleanup rules.
Worked example — sharing a cleanup profile
- Open Settings → Editor → Code Cleanup and create a profile named “TeamStandard”.
- Enable Reformat code, Remove redundant using directives, Convert foreach to LINQ, and Enforce naming conventions.
- Click Export and save as
TeamStandard.dotsettingsin the repo root. - Commit the file; teammates receive it via Manage Layers and can activate it with one click.
Cross‑project refactoring in practice
Because refactorings operate on the PSI, they update every call site even when a target project is unloaded. Consider renaming IRepository to IDataStore across three projects: a domain library, an ASP.NET Core API, and a Razor Pages UI.
// Domain library
public interface IRepository { Task<T> GetByIdAsync(int id); }
// API project
public class ProductController : ControllerBase {
private readonly IRepository _repo;
public ProductController(IRepository repo) => _repo = repo;
}
// UI project (Razor)
@inject IRepository Repo
Steps:
- Place caret on
IRepositoryin the domain project. - Press Ctrl+R, Ctrl+R (Rename).
- Type
IDataStoreand enable Search in comments and string literals to catch DI container registrations inappsettings.jsonor XML config. - Press Enter. Rider updates the interface, the constructor parameter, the Razor
@injectdirective, and any matching string literals.
If the interface is referenced via reflection (e.g., typeof(IRepository).AssemblyQualifiedName), the rename will not touch those strings unless the Search in comments and string literals toggle is on — but that toggle often produces false positives in large codebases.
Performance trade‑offs and mitigation
| Symptom | Cause | Mitigation |
|---|---|---|
| 2–5 min initial indexing on >100 projects | Full PSI build for all projects | Enable Power Save Mode (defers analysis until explicit save) or disable solution‑wide analysis for rarely changed projects via .editorconfig. |
| 2–4 GB heap, GC pauses on <16 GB RAM | Large in‑memory index | Add -Xmx4g–-Xmx6g to rider64.exe.vmoptions (or rider.vmoptions on macOS/Linux). |
| Noisy diffs in generated files (Designer.cs, .g.cs) | Code Cleanup reformats generated code | Exclude generated file patterns in the cleanup profile (Do not reformat → add *.Designer.cs, *.g.cs). |
| Conflicting severity levels in mixed Unity / non‑Unity solutions | Unity inspection profile overrides defaults | Create a unified .editorconfig with explicit severity entries for shared rules. |
You can verify heap usage during indexing with Help → Diagnostic Tools → Memory Usage and watch the status bar for indexing progress. Exporting an Inspect Code → Whole Solution report before and after tuning gives a concrete baseline of violation counts.
Actionable checklist
- Confirm solution‑wide analysis is on: Settings → Editor → Inspection Settings → Solution‑Wide Analysis.
- Allocate 4–6 GB heap via
-Xmxin the appropriate.vmoptionsfile. - Commit a shared
.dotsettingscleanup profile and verify teammates receive it through Manage Layers. - Test a cross‑project rename on a public interface used in at least three projects; check XAML, Razor, and
.csprojPackageReferenceversion attributes for updates. - If indexing time is unacceptable, disable analysis per‑project with
dotnet_analyze_scope = projectin.editorconfigfor low‑churn modules.
Rider’s PSI gives you IDE‑level refactoring safety across project boundaries, but the power comes with memory pressure and configuration decisions. By tuning heap, sharing cleanup profiles, and selectively scoping analysis, you keep the productivity gains without the slowdown.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.