name: performance-audit description: Performance audit of the codebase — identifies N+1 queries, missing indexes, slow queue jobs, unoptimized data access patterns, and Redis cache opportunities. Produces a prioritized report. license: MIT compatibility: NestJS + Next.js monorepo metadata: author: project version: "1.0"
Audit this NestJS + Next.js monorepo for performance issues. Focus on database access patterns, queue configuration, caching, and response size.
Do not modify anything. This is a read-only analysis.
Audit Areas
1. Database — N+1 Queries
The most common performance killer. Look for loops with database calls inside:
# Find potential N+1 patterns (db call inside loop)
grep -r "for.*await.*this\.db\|forEach.*await.*this\.db\|map.*await.*this\.db" apps --include="*.ts" -n
# Find missing 'include' on relations
grep -r "this\.db\.\w*\.findMany\|this\.db\.\w*\.findFirst" apps --include="*.ts" -n
For each findMany, check:
- Are related entities fetched in a loop? → N+1
- Should they be included with
include: { ... }? - Is a
selectclause limiting fields returned?
2. Database — Missing Indexes
# Check schema for @index annotations
grep -r "@@index\|@index" packages/database/prisma --include="*.prisma" -n
# Find columns used in where clauses that may lack indexes
grep -r "where:.*{" apps --include="*.ts" -n
For each field used in where, orderBy, or cursor, verify a @@index exists in the schema.
3. Pagination
# Find queries without pagination
grep -r "findMany(" apps --include="*.ts" -n | grep -v "take\|skip"
# Verify PaginatedUtil usage
grep -r "PaginatedUtil\|paginationSchema" apps --include="*.ts" -n
- Every
findManyon a potentially large collection should haveskip+take takeshould be capped (max 100 viapaginationSchema)
4. Bull Queue Configuration
# Check job options
grep -r "attempts\|backoff\|removeOnComplete\|removeOnFail" apps --include="*.ts" -n
# Check for unbounded queues
grep -r "removeOnFail\|removeOnComplete" apps --include="*.ts" -n
Required job options (per CLAUDE.md):
attempts: 3backoff: { type: 'exponential', delay: 2000 }removeOnComplete: trueremoveOnFail: 500
Missing removeOnFail → unbounded Redis memory growth.
5. Redis — Cache Opportunities
# Check for repeated identical DB queries
grep -r "this\.db\." apps --include="*.ts" -n | sort | uniq -c | sort -rn | head -20
Look for:
- Repeated lookups by ID (user by ID on every request)
- Static/slow-changing data (config, roles) fetched per request
- Session data fetched multiple times per request
6. HTTP Response Size
# Check for missing select clauses (fetching entire models)
grep -r "findMany({\s*where\|findFirst({\s*where\|findUnique({\s*where" apps --include="*.ts" -n | grep -v "select"
Always use select to return only needed fields — especially on list endpoints.
7. Next.js Performance
# Check for client components that could be server components
grep -r "'use client'" apps/web --include="*.tsx" -n
# Check for missing Suspense boundaries
grep -r "async.*export default function\|await.*fetch" apps/web/src/app --include="*.tsx" -n
- Data fetching should happen in server components where possible
- Add
loading.tsxfiles for route-level Suspense boundaries - Check for unused client-side state management
8. Logging Overhead
# Check logging in hot paths
grep -r "this\.logger\.\|console\.\|Logger\." apps --include="*.ts" -n | grep -v "error\|warn"
- Debug/verbose logging in hot paths (health checks, frequent events) → overhead
- Verify health check paths are silenced (
/health,/metricsin pino config)
9. Throttling Configuration
grep -r "ThrottlerModule\|ttl\|limit" packages/shared/src --include="*.ts" -n
Default: 10 req / 60s per IP. Evaluate if this is appropriate for each endpoint type.
Output Format
## Performance Audit Report
### CRITICAL (Blocking production scale)
| # | Issue | Location | Estimated Impact |
|---|-------|----------|-----------------|
| 1 | N+1 on user.findMany (relations loaded in loop) | apps/api/src/users.service.ts:45 | O(n) queries |
### HIGH (Address soon)
| # | Issue | Location | Recommendation |
|---|-------|----------|---------------|
### MEDIUM (Optimization opportunity)
| # | Issue | Location | Recommendation |
|---|-------|----------|---------------|
### PASSED CHECKS
- ✓ All findMany calls paginated
- ✓ removeOnFail set on all queue jobs
- ...
### Quick Wins
- [ ] Add `include` to users.findMany at users.service.ts:45
- [ ] Cache config lookup at config.service.ts:23 (changes rarely)
Guardrails
- Never modify code — read only
- Estimate query count impact where possible (O(1) vs O(n))
- Distinguish between "will cause issues at scale" vs "already causing issues"
- Reference specific file paths and line numbers for every finding