Traces a GraphQL resolver tree to locate the N+1 pattern (one parent query returns N rows, then a child field resolver fires once per row), classifies every child field resolver as safe or N+1 risk, and applies one of three fixes: per-request DataLoader batching, eager projection in the parent resolver, or selection-set-aware prefetch. Use when a list-returning resolver is added or changed in review, when a connection-pool exhaustion or slow-query alert traces back to GraphQL traffic, or when a resolver trace shows a child field resolved once per parent row.
80
100%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Extended contracts and cautions for the three fixes in Step 3. The core runnable code for each fix stays inline in SKILL.md; this file holds the detail you consult once you have picked a fix.
DataLoader coalesces all loads within a single tick of the event loop into
one batch call
(github.com/graphql/dataloader),
so every .load() the executor issues for the same field across N parents
lands in one batch call.
Two contracts the batch function must honour, both from the DataLoader README:
A findMany returns rows in database order and drops missing ids, so the
re-map line in the inline example is mandatory, not decoration. Skipping it
silently attributes one parent's data to another parent.
Scope every loader to a single request. DataLoader memoizes loads within one request, and the README warns against sharing an instance across users, which can leak cached data into each request. Construct loaders when a request begins and discard them when it ends. A module-level loader shared across requests is a cache-poisoning defect that leaks one user's rows into another user's response. Treat a loader constructed outside per-request context setup as a finding in its own right, independent of any N+1.
Fix B is the eager-loading remedy: the EF Core guide recommends eager loading over lazy loading so the data comes back in one roundtrip, and warns that lazy loading makes it easy to trigger N+1 inadvertently (learn.microsoft.com).
Cost to weigh before choosing B: eagerly joining a one-to-many relation duplicates the parent columns across every child row. The same EF Core page names this the "cartesian explosion" problem and notes that as more one-to-many relationships are loaded, the duplicated data may grow and hurt performance. Prefer B for to-one relations and for to-many relations with small fan-out.
parseResolveInfo from graphql-parse-resolve-info turns the fourth
resolver argument into a tree whose fieldsByTypeName is an object keyed by
GraphQL object type names, whose values are objects keyed by the requested
field aliases
(github.com/graphile/graphile-engine).
C is B with a condition: it pays a small parsing cost per request to avoid
paying the projection cost on queries that never ask for the field.