Universal N+1 Query Detector
Find N+1 queries at runtime, in any language, without leaving your editor.
Laravel, Django, Prisma today — Rails, Hibernate, EF Core, GORM and anything else as soon as
someone writes a 200-line probe. One detection engine, one open format, every stack.
How it works
Any app + probe → JSONL event log → extension watches + groups → inline warnings
The extension never parses your source code and has no idea what framework you are running. It
reads one open format — one JSON object per query, appended to .nplus1/queries.jsonl — groups
identical queries by call site, and draws a warning on the line that issued them.
What you get
- Inline warning at the end of the offending line:
⚠ 47 queries (N+1)
- Problems panel entry, so it appears where you already look for issues
- Hover with the query, the count, the total time, and the eager-loading fix for your ORM
- Status bar count for the current file
- Background jobs too — queue workers, cron tasks and CLI scripts have N+1 problems and no
request scope, so a time-window fallback covers them
Setup
The extension needs a probe writing the log. Pick yours.
The probes are not on Packagist, PyPI or npm yet — install them from the repo with the commands
below. They work today; the registry names are reserved for the first tagged release.
Laravel — clone the repo beside your app, add it as a path repository, then:
composer require --dev nplus1/laravel-probe:@dev
Auto-discovery does the rest. Active only when APP_ENV=local.
Django — pip installs straight from the repo subdirectory:
pip install "git+https://github.com/mosawerghousi/n-plus-one-detector.git#subdirectory=probes/python-django"
INSTALLED_APPS = [..., "nplus1_probe"]
MIDDLEWARE = ["nplus1_probe.middleware.Nplus1TraceMiddleware", ...]
Active only when DEBUG = True.
Prisma — build once, then install by path:
git clone https://github.com/mosawerghousi/n-plus-one-detector.git
cd n-plus-one-detector/probes/node-prisma && npm install && npm run build
cd /path/to/your/app && npm install --save-dev /path/to/n-plus-one-detector/probes/node-prisma
import { withNplus1Probe } from 'nplus1-prisma-probe';
export const prisma = withNplus1Probe(new PrismaClient());
Inert when NODE_ENV=production.
Then load the page or run the job, and the warnings appear. Full per-probe instructions live in
the repo.
Another stack? Writing a probe is 150–250 lines and needs no change to this extension. See
probes/TEMPLATE.md
and the format spec.
Settings
| Setting |
Default |
What it does |
nplus1.threshold |
5 |
Identical queries from one call site before it is reported |
nplus1.enabled |
true |
Master switch |
nplus1.logPath |
.nplus1/queries.jsonl |
Log path, relative to each workspace folder |
nplus1.timeWindowMs |
2000 |
Grouping window when a probe reports no trace id |
nplus1.pathMapping |
{} |
Container path → local path |
nplus1.ignorePatterns |
[] |
Globs whose findings are suppressed |
Running in Docker, Sail, a devcontainer, or against a remote interpreter? Set the mapping, or
paths will not resolve:
{ "nplus1.pathMapping": { "/var/www/html": "/Users/me/projects/my-app" } }
Commands
| Command |
What it does |
N+1: Clear Findings and Truncate Log |
Wipes findings and empties the log |
N+1: Toggle Detection |
Turns detection on or off for the workspace |
N+1: Show All Findings |
Quick-pick list of every finding; jumps to the call site |
Supported ORMs
Fix suggestions are tailored per ORM: Eloquent, Doctrine, Django, SQLAlchemy, Prisma, TypeORM,
Sequelize, Knex, ActiveRecord, Hibernate/JPA, EF Core, GORM. An unrecognised ORM still gets full
detection with a generic eager-loading hint.
Why not Bullet, Telescope, or preventLazyLoading?
Those tools are good — and each is one framework, outside your editor. Bullet is Rails-only.
Telescope is Laravel-only with a separate web UI. preventLazyLoading throws instead of reporting.
django-silk is Django-only.
This is neither single-framework nor out-of-editor: one engine over one open format, warnings on
the line that caused them, based on queries that actually ran rather than static guesses.
Privacy
Everything stays on your machine. The probe writes a local file, the extension reads it, and query
bindings never enter the log — placeholders are left unresolved, which is also what makes identical
queries group without any SQL parsing.
Links
MIT licensed.