EagerEye for VS Code
Catch N+1 queries in your Rails app — on save, right in your editor.
Catch N+1 queries before they hit production — right in your editor.
Table of Contents
Features
On-save Analysis — Runs automatically every time you save a Ruby file. No build step, no test suite needed.
Problem Highlighting — Squiggly underlines show exactly where N+1 queries may occur. Hover for details and suggestions.
Quick Fixes — One-click fixes for common issues (.pluck(:id) → .select(:id), etc.) and inline # eager_eye:disable toggles.
Status Bar Integration — Issue count at a glance, click to jump to the Problems panel.
11 Detector Types — Comprehensive detection covering the most common N+1 patterns in Rails applications.
Installation
Prerequisites
Install the EagerEye gem:
gem install eager_eye
Or add to your Gemfile:
gem "eager_eye", group: :development
Install Extension
Option 1: Search for "EagerEye" in VS Code Extensions (Cmd+Shift+X / Ctrl+Shift+X)
Option 2: Install from VS Code Marketplace
Option 3: Command line:
code --install-extension hamzagedikkaya.eager-eye
Quick Start
- Open a Rails project in VS Code
- Open any Ruby file (controller, model, serializer, etc.)
- Save the file — EagerEye automatically analyzes it
- Issues appear as warnings with squiggly underlines
- Hover over underlined code to see details and suggestions
Detected Issues
EagerEye detects 11 types of N+1 query patterns:
| Detector |
Description |
| Loop Association |
Queries inside iterations (posts.each { \|p\| p.author }) |
| Serializer Nesting |
Association calls in serializer blocks (Blueprinter, AMS, Alba) |
| Missing Counter Cache |
.count/.size calls that could use counter cache |
| Custom Method Query |
.where/.find_by on associations inside loops |
| Count in Iteration |
.count inside loops (always executes query) |
| Callback Query |
N+1 patterns inside ActiveRecord callbacks |
| Pluck to Array |
.pluck(:id) used in where instead of subquery |
| Delegation N+1 |
delegate :method, to: :association calls in loops without preload |
| Decorator N+1 |
Draper / SimpleDelegator / Presenter / ViewObject access without preload |
| Scope Chain N+1 |
Named scopes (.recent, .active) on associations in loops |
| Validation N+1 |
Model.create/save in loops on uniqueness-validated models |
Quick Fixes
- Auto-fix generic N+1 queries where possible.
- Pluck to Select: Safely converts
.pluck(:id) to .select(:id) inside where clauses.
- Smart Safety: Only fixes safe patterns and ignores small collections (Info severity).
Severity Levels
- Error: Critical N+1 queries (e.g.
.all.pluck).
- Warning: Standard N+1 queries.
- Info: Low impact issues or small collections.
Example Detection
# EagerEye will warn about this:
posts.each do |post|
post.author.name # ⚠️ N+1 query detected
post.comments.count # ⚠️ COUNT query for each post
end
# Suggested fix:
posts.includes(:author, :comments).each do |post|
post.author.name # ✓ No additional query
post.comments.size # ✓ No additional query
end
Commands
Access commands via Command Palette (Cmd+Shift+P / Ctrl+Shift+P):
| Command |
Description |
EagerEye: Analyze Current File |
Manually trigger analysis on active file |
EagerEye: Analyze Workspace |
Analyze all Ruby files in workspace |
EagerEye: Clear Diagnostics |
Clear all EagerEye warnings |
Extension Settings
Configure EagerEye in VS Code settings (Cmd+, / Ctrl+,):
| Setting |
Default |
Description |
eagerEye.enable |
true |
Enable/disable the extension |
eagerEye.analyzeOnSave |
true |
Automatically analyze on file save |
eagerEye.gemPath |
eager_eye |
Path to eager_eye executable |
eagerEye.enabledDetectors |
[] |
Specific detectors to enable (empty = all) |
eagerEye.excludePatterns |
["**/spec/**", "**/test/**", "**/vendor/**"] |
Glob patterns to exclude |
Example Configuration
{
"eagerEye.enable": true,
"eagerEye.analyzeOnSave": true,
"eagerEye.excludePatterns": [
"**/spec/**",
"**/test/**",
"**/vendor/**",
"**/legacy/**"
],
"eagerEye.enabledDetectors": [
"loop_association",
"serializer_nesting"
]
}
Extension vs CLI
Both this extension and the EagerEye gem use the same analysis engine. Use whichever fits the moment:
| Use the extension when |
Use the CLI when |
| You're writing code and want feedback on save |
You're setting up CI / pre-commit hooks |
| You want squiggles and hover tooltips |
You want machine-readable JSON output |
| You're reviewing a single file |
You want to scan the whole repo at once |
| You want one-click quick fixes |
You want batch auto-fix (eager_eye --fix --force) |
A typical workflow uses both: extension during development, CLI in CI to gate PRs.
Troubleshooting
"command not found: eager_eye"
The extension shells out to the eager_eye executable. Make sure the gem is installed and on your PATH:
gem install eager_eye
which eager_eye # should print a path
If you use a Ruby version manager (rbenv, rvm, asdf, chruby), make sure VS Code is launched from a shell that has it set up. Or set the absolute path explicitly:
{
"eagerEye.gemPath": "/Users/you/.rbenv/shims/eager_eye"
}
Wrong Ruby version / gem not found in Bundler context
If your project uses a different Ruby than your global install (via .ruby-version), the gem must be installed for that Ruby too:
cd path/to/your/project
gem install eager_eye # installs for the project's Ruby
Or, if you've added it to your Gemfile, run from inside the project:
{
"eagerEye.gemPath": "bundle exec eager_eye"
}
No diagnostics appear after save
- Confirm the file's language mode is Ruby (bottom-right of the status bar).
- Check
eagerEye.enable and eagerEye.analyzeOnSave are both true (default).
- Open the Output panel → "EagerEye" channel — gem errors are logged there.
- Try the manual command:
EagerEye: Analyze Current File from the Command Palette.
False positives — how to suppress them
Use inline RuboCop-style comments (handled by the gem):
user.posts.count # eager_eye:disable CountInIteration
Full suppression syntax (single-line, next-line, block, file-level) is documented in the gem README.
Performance — large workspaces feel slow
Analyze Workspace opens every Ruby file individually; on huge repos it can take a while. For routine work, lean on on-save analysis (per-file, instant). Use excludePatterns to cut paths you don't care about:
{
"eagerEye.excludePatterns": [
"**/spec/**", "**/test/**", "**/vendor/**", "**/db/migrate/**"
]
}
How It Works
EagerEye uses static analysis with AST (Abstract Syntax Tree) parsing to detect N+1 query patterns without running your code. This means:
- No test suite required — works on any Ruby file
- No runtime overhead — analysis happens at parse time
- Fast feedback — runs on every save
For maximum coverage pair it with Bullet — static analysis catches code paths your tests don't hit, runtime analysis catches what static can't see.
Compatibility
| Component |
Required |
| VS Code |
1.85+ |
| Ruby |
3.1+ |
| EagerEye gem |
1.2.x (latest recommended) |
The extension automatically picks up new detector types added to the gem — no extension update needed.
License
MIT — see LICENSE.
Found a bug? Open an issue · Like the extension? Star the repo ⭐