skills/ballee/db-anti-patterns/SKILL.md
Detection rules and grep patterns for database performance anti-patterns. Use when scanning codebase for N+1 queries, sequential queries, or connection pool issues.
npx skillsauth add javeedishaq/ai-workflow-orchestrator db-anti-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Detection rules and grep patterns for identifying database performance anti-patterns in code.
db-performance-agent for automated detectionQueries executed inside loops - causes O(n) database calls.
Detection Patterns:
// Pattern 1: await inside for loop
for (const item of items) {
await supabase.from('table')... // N+1!
}
// Pattern 2: await inside forEach
items.forEach(async (item) => {
await supabase.from('table')... // N+1!
});
// Pattern 3: await inside map
await Promise.all(items.map(async (item) => {
await supabase.from('table')... // N+1 even with Promise.all!
}));
// Pattern 4: count queries in loop
for (const item of items) {
const { count } = await supabase.from('x').select('id', { count: 'exact' })...
}
Grep Patterns:
# For loops with await supabase
grep -Pzo 'for\s*\([^)]+\)\s*\{[^}]*await[^}]*\.from\(' --include="*.ts"
# forEach with async
grep -n 'forEach\s*\(\s*async' --include="*.ts"
# map with nested await from()
grep -n '\.map\s*\(\s*async.*await.*\.from\(' --include="*.ts"
Severity: CRITICAL Impact: 50-500+ queries per request Auto-fixable: Yes - batch fetch + Map lookup
Multiple await statements that could run in parallel.
Detection Pattern:
// Sequential (BAD)
const a = await supabase.from('table_a').select()...;
const b = await supabase.from('table_b').select()...;
const c = await supabase.from('table_c').select()...;
// Should be parallel (GOOD)
const [a, b, c] = await Promise.all([
supabase.from('table_a').select()...,
supabase.from('table_b').select()...,
supabase.from('table_c').select()...,
]);
Detection Heuristic:
Look for 2+ consecutive lines matching:
const/let X = await supabase.from(...)Severity: HIGH Impact: 2-5x latency increase Auto-fixable: Yes - wrap in Promise.all()
Queries without .limit() on tables that can grow large.
Large Tables to Check:
const LARGE_TABLES = [
'events',
'cast_assignments',
'invoices',
'invoice_line_items',
'notifications',
'notification_deliveries',
'airtable_sync_changes',
'audit_logs',
'feedback_requests',
'reimbursements',
'reimbursement_line_items',
];
Detection Pattern:
// Missing limit (BAD for large tables)
await supabase.from('events').select('*')
// Should have limit or be filtered (GOOD)
await supabase.from('events').select('*').limit(100)
await supabase.from('events').select('*').eq('user_id', userId)
Grep Pattern:
# Selects on large tables without limit
grep -n "\.from\(['\"]events['\"]\)" --include="*.ts" | grep -v "\.limit\|\.eq\|\.in\|\.single"
Severity: MEDIUM Impact: Memory exhaustion, slow queries Auto-fixable: Partial - add .limit(), may need review
Single-row operations that should be batched.
Detection Pattern:
// Individual inserts (BAD)
for (const item of items) {
await supabase.from('table').insert({ ...item });
}
// Individual updates (BAD)
for (const id of ids) {
await supabase.from('table').update({ status: 'done' }).eq('id', id);
}
// Batch operations (GOOD)
await supabase.from('table').insert(items);
await supabase.from('table').update({ status: 'done' }).in('id', ids);
Grep Pattern:
# Insert in loop
grep -Pzo 'for\s*\([^)]+\)\s*\{[^}]*\.insert\(' --include="*.ts"
# Update in loop
grep -Pzo 'for\s*\([^)]+\)\s*\{[^}]*\.update\(' --include="*.ts"
Severity: HIGH Impact: N database round-trips Auto-fixable: Yes - batch operations
Using multiple COUNT queries instead of fetching once and aggregating.
Detection Pattern:
// Multiple count queries (BAD)
const { count: countA } = await supabase.from('x').select('id', { count: 'exact' }).eq('status', 'a');
const { count: countB } = await supabase.from('x').select('id', { count: 'exact' }).eq('status', 'b');
const { count: countC } = await supabase.from('x').select('id', { count: 'exact' }).eq('status', 'c');
// Single fetch + aggregate (GOOD)
const { data } = await supabase.from('x').select('status').in('status', ['a', 'b', 'c']);
const counts = { a: 0, b: 0, c: 0 };
for (const item of data) counts[item.status]++;
Grep Pattern:
# Multiple count queries (look for pattern of consecutive count selects)
grep -n "count: 'exact'" --include="*.ts"
Severity: MEDIUM Impact: 2-10x more queries than necessary Auto-fixable: Yes - single query + in-memory aggregation
Fetching the same related entity type multiple times sequentially.
Detection Pattern:
// Sequential related lookups (BAD)
const user1 = await getUser(id1);
const user2 = await getUser(id2);
const user3 = await getUser(id3);
// Batch lookup (GOOD)
const users = await getUsers([id1, id2, id3]);
Severity: MEDIUM Impact: Increased latency Auto-fixable: Sometimes - depends on function signature
# Find all N+1 patterns (for loops with await from)
grep -rn "for.*{" apps/web --include="*.ts" | xargs -I {} sh -c 'grep -l "await.*\.from\(" {}'
# Find sequential queries (consecutive await from lines)
grep -n "await.*\.from\(" apps/web --include="*.ts" | sort | uniq -c | sort -rn
# Find unbounded selects on large tables
for table in events cast_assignments invoices notifications; do
grep -rn "\.from(['\"]$table['\"])" apps/web --include="*.ts" | grep -v "\.limit\|\.single\|\.eq\|\.in"
done
# Find insert/update in loops
grep -rn "for\s*(" apps/web --include="*.ts" -A 5 | grep -E "\.(insert|update)\("
# Find multiple count queries in same file
grep -l "count: 'exact'" apps/web --include="*.ts" -r | xargs -I {} grep -c "count: 'exact'" {} | grep -v ":1$"
| Severity | Impact | Fix Priority | |----------|--------|--------------| | CRITICAL | 10x+ queries, pool exhaustion risk | Immediate | | HIGH | 3-10x queries/latency | Same sprint | | MEDIUM | 2-3x queries/latency | Next sprint | | LOW | Minor inefficiency | Backlog |
High-risk file patterns to prioritize scanning:
app/api/cron/*/route.ts**/services/*.service.tsapp/admin/**/actions.ts**/reporting*.tsdb-performance-patterns - Correct patterns and fixesdb-performance-agent - Automated scanning and fixingtools
# Test Patterns Testing patterns for reliable, maintainable, and fast tests. > **Template Usage:** Customize for your test framework (Vitest, Jest, Playwright, etc.) and assertion library. ## Test Structure ```typescript // user.test.ts import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { userService } from '@/services/user.service'; import { createTestUser, cleanupTestData } from '@/tests/helpers'; describe('UserService', () => { let testUserId: string; befor
tools
# State Management Patterns Client-side state management patterns for modern applications. > **Template Usage:** Customize for your state library (React Query, Zustand, Jotai, Redux, etc.). ## State Categories | Type | Description | Solution | |------|-------------|----------| | **Server State** | Data from API/database | React Query, SWR | | **Client State** | UI state, user preferences | Zustand, Jotai, useState | | **Form State** | Form inputs, validation | React Hook Form, Formik | | **U
development
# Service Patterns Service layer patterns for clean architecture with proper error handling, logging, and type safety. > **Template Usage:** Customize for your ORM (Prisma, Drizzle, TypeORM, etc.) and logging solution. ## Result Type Pattern Never throw exceptions from services. Always return a Result type. ```typescript // lib/result.ts export type Result<T, E = Error> = | { success: true; data: T } | { success: false; error: E }; export function ok<T>(data: T): Result<T, never> { r
testing
# Row-Level Security Patterns Database security patterns for multi-tenant and user-scoped data. > **Template Usage:** Customize for your database (PostgreSQL, Supabase, etc.) and auth system. ## RLS Fundamentals ### Enable RLS on Tables ```sql -- Enable RLS (required before policies take effect) ALTER TABLE users ENABLE ROW LEVEL SECURITY; ALTER TABLE posts ENABLE ROW LEVEL SECURITY; ALTER TABLE comments ENABLE ROW LEVEL SECURITY; -- Force RLS for table owners too (recommended) ALTER TABLE