skyasu2 / diagnosing-nextjs-performance
Install for your project team
Run this command in your project directory to install the skill for your entire team:
mkdir -p .claude/skills/diagnosing-nextjs-performance && curl -o .claude/skills/diagnosing-nextjs-performance/SKILL.md https://fastmcp.me/Skills/DownloadRaw?id=264
Project Skills
This skill will be saved in .claude/skills/diagnosing-nextjs-performance/ and checked into git. All team members will have access to it automatically.
Important: Please verify the skill by reviewing its instructions before using it.
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.
1 views
0 installs
Skill Content
---
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**:
```bash
# 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**:
```typescript
// 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**:
```bash
# 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**:
```bash
# 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**:
```typescript
// Production build targets
- Main Bundle: < 500KB ✅
- First Load JS: < 200KB ✅
- Route Chunks: < 100KB each
- Total Bundle: ~87MB saved (dev/prod 분리 완료)
```
**Runtime Analysis**:
```bash
# 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**:
```bash
# 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**:
```typescript
// 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
```typescript
// Before
import HeavyComponent from './HeavyComponent';
// After
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <Spinner />,
});
```
### Fix 2: Parallel Server Actions
```typescript
// Before
const data1 = await fetchData1();
const data2 = await fetchData2();
// After
const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
```
### Fix 3: Memoize Components
```typescript
// 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)