Fetching entire follower lists in a single unbounded query is a time-bomb proportional to your most-followed user. At 10,000 followers, a findMany with no take limit loads tens of thousands of joined records into memory, blows through Supabase row limits, and produces multi-second response times. This is a performance-efficiency failure under ISO 25010:2011 — the system cannot maintain acceptable response times as data volume grows. Power users are exactly the accounts that drive retention; making their profiles unusably slow is a direct business impact.
High because unbounded follower queries fail visibly at scale, producing timeouts and errors precisely for the high-profile users whose profiles receive the most traffic.
Switch follower and following list endpoints to cursor-based pagination in app/api/users/[id]/followers/route.ts. Cap the maximum page size at 100 and return a nextCursor so the client can load more incrementally.
// app/api/users/[id]/followers/route.ts
export async function GET(req: Request, { params }: { params: { id: string } }) {
const url = new URL(req.url)
const cursor = url.searchParams.get('cursor') ?? undefined
const limit = Math.min(parseInt(url.searchParams.get('limit') ?? '20'), 100)
const rows = await db.follow.findMany({
where: { followedId: params.id },
take: limit + 1,
skip: cursor ? 1 : 0,
cursor: cursor ? { id: cursor } : undefined,
orderBy: { createdAt: 'desc' },
select: { id: true, follower: true }
})
const hasMore = rows.length > limit
const items = hasMore ? rows.slice(0, limit) : rows
return Response.json({
followers: items.map(r => r.follower),
nextCursor: hasMore ? items[items.length - 1]?.id : null
})
}
ID: community-social-engagement.follow-graph.connection-list-pagination
Severity: high
What to look for: Enumerate all relevant files and Examine routes that display followers/following lists (e.g., /users/[id]/followers, /users/[id]/following). Check whether queries use pagination: cursor-based pagination (Relay-style) or limit/offset. Verify that the implementation does NOT fetch all followers at once (which would fail for power users with thousands of followers).
Pass criteria: At least 1 conforming pattern must exist. Followers and following lists use pagination. Queries include limit and either offset or cursor parameters. The UI supports loading more results incrementally.
Fail criteria: Followers lists fetch all results in a single query, or no pagination mechanism exists, or the API returns unlimited results.
Skip (N/A) when: Follower/following lists are not displayed to users.
Detail on fail: "GET /api/users/[id]/followers returns all followers without pagination — query fails for users with 10k+ followers" or "No limit parameter enforced on followers endpoint"
Remediation: Implement cursor-based or offset pagination for relationship lists:
// app/api/users/[id]/followers/route.ts
export async function GET(req: Request, { params }) {
const { limit = '20', cursor } = Object.fromEntries(
new URL(req.url).searchParams
)
const followers = await db.follow.findMany({
where: { followedId: params.id },
take: Math.min(parseInt(limit), 100),
skip: cursor ? 1 : 0,
cursor: cursor ? { id: cursor } : undefined,
orderBy: { createdAt: 'desc' },
select: { follower: true }
})
return Response.json({
followers: followers.map(f => f.follower),
nextCursor: followers[followers.length - 1]?.id || null
})
}