Claude Code Plugins

Community-maintained marketplace

Feedback

diagnosing-nextjs-performance

@mattnigh/skills_collection
0
0

Next.js Router performance analysis and bottleneck identification workflow. Triggers when user reports performance issues, slow routing, or requests Next.js optimization analysis. Use for identifying FCP/LCP/CLS bottlenecks and Server Actions blocking.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name diagnosing-nextjs-performance
version v1.1.0
description Next.js Router performance analysis and bottleneck identification workflow. Triggers when user reports performance issues, slow routing, or requests Next.js optimization analysis. Use for identifying FCP/LCP/CLS bottlenecks and Server Actions blocking.

Next.js Router Performance Diagnosis

Target Token Efficiency: 75% (400 tokens → 100 tokens)

Purpose

Automated Next.js routing performance analysis and bottleneck identification without manual investigation.

Trigger Keywords

  • "performance issues"
  • "slow routing"
  • "next router bottleneck"
  • "페이지 느림"
  • "라우팅 성능"
  • "performance check"
  • "bottleneck analysis"
  • "성능 분석"
  • "web vitals"
  • "optimize routing"
  • "페이지 최적화"
  • "느린 로딩"
  • "performance diagnosis"

Context

  • Framework: Next.js 16 (App Router)
  • Target FCP: < 1.8s (Google 권장)
  • Current FCP: 608ms (우수)
  • Target Response: < 1s
  • Current Response: 532ms (우수)

Workflow

1. Check Current Metrics

Automated Metrics Collection:

# Run performance test
npm run dev:stable &
DEV_PID=$!
sleep 30  # Wait for startup

# Collect metrics (if available)
curl -s http://localhost:3000 -w "
Response Time: %{time_total}s
"

# Kill dev server
kill $DEV_PID

Performance Indicators:

// Parse from logs/performance/ or real-time collection
- FCP (First Contentful Paint): 608ms ✅
- LCP (Largest Contentful Paint): [to be measured]
- TTFB (Time to First Byte): [to be measured]
- Response Time: 532ms ✅
- Bundle Size: 최적화 완료 (87MB 절약)

Metrics Parsing Logic:

# Check if performance logs exist
if [ -f "logs/performance/latest.log" ]; then
  grep -E "(FCP|LCP|TTFB)" logs/performance/latest.log
else
  echo "⚠️  No performance logs found. Metrics will be estimated."
fi

2. Identify Common Bottlenecks

Checklist:

  • Dynamic imports 미사용 (컴포넌트 지연 로드)
  • Server Actions blocking (await 체인)
  • Middleware overhead (auth 체크)
  • Large bundle size (vendor chunks)
  • Unnecessary re-renders (useEffect 의존성)

3. Run Diagnostic Commands

Automated Bundle Analysis:

# Run production build and capture output
BUILD_OUTPUT=$(npm run build 2>&1)

# Parse bundle sizes from build output
echo "$BUILD_OUTPUT" | grep -E "(Route|First Load JS)" | tee logs/performance/bundle-analysis.log

# Extract key metrics
MAIN_BUNDLE=$(echo "$BUILD_OUTPUT" | grep -E "/_app" | awk '{print $4}')
TOTAL_SIZE=$(echo "$BUILD_OUTPUT" | grep -E "First Load JS shared by all" | awk '{print $6}')

# Threshold checks
echo "📦 Bundle Analysis:"
echo "  Main Bundle: $MAIN_BUNDLE"
echo "  Total First Load: $TOTAL_SIZE"

# Warning thresholds
if [[ $(echo "$MAIN_BUNDLE" | sed 's/kB//') > 500 ]]; then
  echo "⚠️  WARNING: Main bundle exceeds 500KB threshold"
fi

Bundle Size Targets:

// Production build targets
- Main Bundle: < 500KB ✅
- First Load JS: < 200KB ✅
- Route Chunks: < 100KB each
- Total Bundle: ~87MB saved (dev/prod 분리 완료)

Runtime Analysis:

# Check dev server performance
time npm run dev:stable &
DEV_PID=$!
sleep 5

# Measure startup time
STARTUP_TIME=$(ps -p $DEV_PID -o etime= | tr -d ' ')
echo "⏱️  Dev Server Startup: $STARTUP_TIME"

# Expected: < 22초 (current: 22초, 35% improved)
kill $DEV_PID

4. Analyze Web Vitals

Check Core Web Vitals:

  • FCP: < 1.8s (현재 608ms ✅)
  • LCP: < 2.5s (target)
  • CLS: < 0.1 (layout shift)
  • INP: < 200ms (interaction)

5. Bottleneck Classification

Automated Performance Regression Detection:

# Load baseline metrics (from docs/status.md)
BASELINE_FCP=608
BASELINE_RESPONSE=532
BASELINE_STARTUP=22

# Parse current metrics from latest performance log
CURRENT_FCP=$(awk '/FCP:/ {gsub(/ms/, "", $2); print $2}' logs/performance/latest.log 2>/dev/null || echo "0")
CURRENT_RESPONSE=$(awk '/Response:/ {gsub(/ms/, "", $2); print $2}' logs/performance/latest.log 2>/dev/null || echo "0")
CURRENT_STARTUP=$(awk '/Startup:/ {gsub(/s/, "", $2); print $2}' logs/performance/latest.log 2>/dev/null || echo "0")

# Calculate percentage differences
FCP_DIFF=$(echo "scale=1; ($CURRENT_FCP - $BASELINE_FCP) / $BASELINE_FCP * 100" | bc 2>/dev/null || echo "0")
RESPONSE_DIFF=$(echo "scale=1; ($CURRENT_RESPONSE - $BASELINE_RESPONSE) / $BASELINE_RESPONSE * 100" | bc 2>/dev/null || echo "0")
STARTUP_DIFF=$(echo "scale=1; ($CURRENT_STARTUP - $BASELINE_STARTUP) / $BASELINE_STARTUP * 100" | bc 2>/dev/null || echo "0")

# Trigger warnings for >10% regression
echo "📊 Performance Regression Check:"
if (( $(echo "$FCP_DIFF > 10" | bc -l 2>/dev/null || echo 0) )); then
  echo "⚠️  WARNING: FCP regression ${FCP_DIFF}% (${BASELINE_FCP}ms → ${CURRENT_FCP}ms)"
fi
if (( $(echo "$RESPONSE_DIFF > 10" | bc -l 2>/dev/null || echo 0) )); then
  echo "⚠️  WARNING: Response time regression ${RESPONSE_DIFF}% (${BASELINE_RESPONSE}ms → ${CURRENT_RESPONSE}ms)"
fi
if (( $(echo "$STARTUP_DIFF > 10" | bc -l 2>/dev/null || echo 0) )); then
  echo "⚠️  WARNING: Startup time regression ${STARTUP_DIFF}% (${BASELINE_STARTUP}s → ${CURRENT_STARTUP}s)"
fi

Bundle Size Thresholds:

// Check against production targets
const THRESHOLDS = {
  mainBundle: 500, // KB - trigger investigation if exceeded
  firstLoad: 200, // KB - Next.js recommendation
  routeChunk: 100, // KB - per route target
};

// Current status (docs/status.md)
// Main Bundle: ✅ < 500KB
// First Load: ✅ < 200KB
// Total saved: 87MB (dev/prod split)

Categories:

Category A: Bundle Bloat (⚠️ Threshold: Main bundle > 500KB)

  • Symptoms: Large bundle size, slow initial load, high First Load JS
  • Common causes:
    • Unnecessary dependencies in production
    • Missing tree-shaking
    • Large libraries not code-split
    • Inline data/assets
  • Quick fix: Check npm run build output for large chunks
  • Impact: FCP +30-50%, Initial load +2-5s

Category B: Server Component Issues (⚠️ Threshold: Response time > 532ms baseline)

  • Symptoms: Slow SSR, high TTFB, delayed hydration
  • Common causes:
    • Server Components fetching in waterfall
    • Missing Suspense boundaries
    • Blocking database queries
    • No streaming/partial prerendering
  • Quick fix: Add loading.tsx and Suspense
  • Impact: TTFB +50-100%, Response +200-500ms

Category C: Client State Overhead (⚠️ Threshold: Startup time > 22s baseline)

  • Symptoms: Slow client-side navigation, high hydration time
  • Common causes:
    • Too many Client Components ("use client")
    • Large client-side state
    • Unnecessary re-renders
    • Missing React.memo/useMemo
  • Quick fix: Convert to Server Components where possible
  • Impact: Hydration +20-40%, Dev server +35% slower

Category D: Data Fetching (⚠️ Threshold: FCP > 608ms baseline)

  • Symptoms: Slow route transitions, loading spinners
  • Common causes:
    • Waterfall requests
    • No request deduplication
    • Missing caching headers
    • No prefetching
  • Quick fix: Use Next.js fetch() with cache
  • Impact: Route transitions +100-300ms

6. Report Format

🚀 Next.js Performance Analysis

📊 Current Metrics:
├─ FCP: 608ms (✅ < 1.8s)
├─ Response: 532ms (✅ < 1s)
├─ Bundle: Optimized (87MB saved)
└─ Dev Startup: 22s (✅ target)

🔍 Bottlenecks Detected:
1. [Category] - Description
   └─ Location: src/path/to/file.ts:line
   └─ Impact: High/Medium/Low
   └─ Fix: Specific action

🎯 Recommendations:
├─ Priority 1: [Fix description]
├─ Priority 2: [Fix description]
└─ Priority 3: [Fix description]

✅ Already Optimized:
├─ Bundle size (dev/prod 분리)
├─ FCP (608ms)
└─ Response time (532ms)

Token Optimization Strategy

Before (Manual):

User: "Next.js 라우팅이 느려요"
Assistant: [reads performance logs, checks bundle, analyzes code, explains metrics, suggests fixes]
Tokens: ~400

After (Skill):

User: "slow routing"
Skill: [runs diagnostics, reports bottlenecks, provides fixes]
Tokens: ~100 (75% reduction)

Efficiency Gains:

  • ❌ No need to explain Web Vitals
  • ❌ No need to read performance docs
  • ✅ Direct metric collection
  • ✅ Categorized bottleneck analysis

Common Fixes

Fix 1: Dynamic Import

// Before
import HeavyComponent from './HeavyComponent';

// After
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <Spinner />,
});

Fix 2: Parallel Server Actions

// Before
const data1 = await fetchData1();
const data2 = await fetchData2();

// After
const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);

Fix 3: Memoize Components

// Before
export default function Dashboard() { ... }

// After
export default React.memo(Dashboard);

Success Criteria

  • FCP: < 1.8s maintained
  • Response: < 1s maintained
  • Bottlenecks identified: < 3분
  • Specific fixes provided
  • No manual code reading required

Related Skills

  • tests/lint-smoke.md - If performance tests fail
  • documentation/ai-report-export.md - To document findings

Edge Cases

Case 1: No Bottlenecks Detected

  • Report: "All metrics within target"
  • Action: No performance issues

Case 2: Build Fails

  • Check: TypeScript errors
  • Fallback: Use dev server metrics

Case 3: Metrics Unavailable

  • Run: npm run dev to collect data
  • Wait: 30s for initial load

Changelog

  • 2025-12-12: v1.1.0 - Tech stack upgrade alignment
    • Next.js 15 → 16 framework version update
  • 2025-11-04: v1.0.0 - Initial implementation (Phase 1)