Skip to content
Back to skills

Perf Audit

ASecurity

Performance audit: bundle size, lazy loading, data fetching, caching, N+1 queries, image optimization. Native mode checks memory, I/O, launch weight, energy.

  • 4 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 9, 2026
developmentpythonrustgoswiftkotlinshellbashreactnextjsexpress

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned October 9, 2026

npx -y skills add marcoguillermaz/Tierward --skill perf-audit --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Perf Audit?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Perf Audit
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/marcoguillermaz-perf-audit/badge)](https://www.skillsdirectory.com/skills/marcoguillermaz-perf-audit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: perf-audit
description: Performance audit: bundle size, lazy loading, data fetching, caching, N+1 queries, image optimization. Native mode checks memory, I/O, launch weight, energy.
user-invocable: true
model: sonnet
context: fork
allowed-tools: Read Glob Grep Bash Agent Edit Write
argument-hint: [target:section:<section>|target:page:<route>|mode:audit|mode:apply]
---

## Configuration (adapt before first run)

> Replace these placeholders:
> - `[FRAMEWORK]` - e.g. `Next.js App Router`, `Remix`, `SvelteKit`, `plain React`
> - `[SITEMAP_OR_ROUTE_LIST]` - e.g. `docs/sitemap.md`
> - `[API_ROUTES_PATH]` - e.g. `routes/`, `src/handlers/`, `api/`
> - `[BUNDLE_TOOL]` - e.g. `@next/bundle-analyzer`, `vite-bundle-visualizer`, `webpack-bundle-analyzer`
> - `[PERF_TOOL]` - profiling tool for native/backend stacks - e.g. `Instruments` (Swift), `Android Profiler` (Kotlin), `perf` / `flamegraph` (Rust/Go), `cProfile` (Python), `dotnet-trace` (.NET). If not configured, the skill runs static analysis only and recommends profiling setup.
> - `[PROFILER_COMMAND]` - command to generate a profile - e.g. `xcrun xctrace record --template 'Time Profiler'`, `go tool pprof`, `cargo flamegraph`, `python -m cProfile -o profile.out`. If not configured, the skill skips the profiling step and proceeds with static analysis.
> - Note: if this is a **public-facing** app, remove the "Out of scope" restriction on Core Web Vitals

## Applicability check

Before any other step: read `CLAUDE.md` and check the Framework and Language fields.

- If the project is a **web application** (Framework is NOT `N/A - native app` and NOT `N/A - no web frontend`): proceed to **Step 1 - Web Performance Audit** (Steps 1–5).
- If the project is a **native or backend-only application** (Framework is `N/A - native app` or `N/A - no web frontend`): skip Steps 1–5 and proceed directly to **Step 6 - Native/Backend Performance Audit**.



## Context and scope

**In scope**: bundle composition, server/client component boundaries, dynamic rendering triggers, lazy loading, data fetching efficiency (caching, parallelism, N+1), re-render patterns, image optimization. For native stacks: algorithmic complexity, stack-specific hot-path patterns, memory management, launch weight, energy impact, binary size.
**Out of scope**: SEO, CWV as ranking signals, `robots.txt`, `sitemap.xml`, OG tags, Lighthouse site audit, accessibility (→ `/ui-audit`), DB schema (→ `/skill-db`).
**Default mode**: audit (report only, no code changes). `mode:apply` makes focused non-breaking fixes.

**CWV reference (informational only - not primary deliverable for this internal app):**

| Metric | Good | Needs work | Poor | Primary cause |
|---|---|---|---|---|
| LCP | ≤ 2.5s | 2.5–4s | > 4s | Slow server response, render-blocking resources |
| CLS | ≤ 0.1 | 0.1–0.25 | > 0.25 | Unsized images, dynamic content above fold |
| INP | ≤ 200ms | 200–500ms | > 500ms | Blocking JS on event handlers |

Source: web.dev/articles/vitals. Use these thresholds only as triage anchors - not as primary deliverables.

---

## Step 0 - Target resolution

Parse `$ARGUMENTS` for `target:` and `mode:` tokens.

**Operating modes:**
| Mode | Behavior |
|---|---|
| `mode:audit` (default) | Report only - no code changes |
| `mode:apply` | Apply focused, non-breaking fixes (lazy loading wrappers, `Promise.all` parallelization). Describe each change before applying. |

**Target resolution:**
| Pattern | Meaning |
|---|---|
| `target:page:/dashboard` | Focus on the dashboard and its component tree (example) |
| No argument | **Full audit - ALL page files + layout files + lib files + API routes from sitemap.md. Maximum depth.** |

**STRICT PARSING - mandatory**: derive target ONLY from the explicit text in `$ARGUMENTS`. Do NOT infer target from conversation context, recent work, active block names, or project memory. If `$ARGUMENTS` contains no `target:` token → full audit across ALL files from sitemap.md at maximum depth. When a target IS provided → act with maximum depth and completeness on that specific scope only.

**Target scoping - comparative vs independent checks (mandatory):** a subset of checks evaluate a *project-wide property* (build configuration, client bundle composition, launch entry point, release artifact); the rest evaluate one file or route in isolation.
- **Comparative checks - full-project by design; the `target:` filter does NOT apply to them:** P1, P2, P3 (web) and NR1, NR4 (native). They MUST run against the full project even when a target is given. The client bundle, build configuration, entry point, and release artifact are global - narrowing them to the target subset hides cross-cutting exposure (a heavy package bundled by a non-targeted page still ships to every user).
- **Independent checks - target-safe:** every other check (B1-B9, Q1-Q3, NP1-NP4, Step 6b, NR2, NR3) evaluates a single file/route and safely honors the `target:` filter. Layout/shell files stay in scope regardless of target (Step 1).
- When a `target:` is given: apply the filter to the independent checks only; run the comparative checks across the full project and state in the report that they ran full-project by design.

Announce: `Running perf-audit - scope: [FULL | target: <resolved>] - mode: [audit | apply]`
Apply the target filter to the file list in Step 1.

---

## Step 1 - Build file inventory

- All page/view files in scope
- All heavy components (those with chart, calendar, data table, rich text editor - high rendering cost)
- All layout/shell files (always include regardless of target - critical for B1 Flag B and B8)
- All service/data-access files directly called from page/component files - exclude pure utility files with no DB calls
- Framework configuration file (e.g. `next.config.ts`, `vite.config.ts`, `nuxt.config.ts`, `webpack.config.js`)

Read `docs/refactoring-backlog.md` - note existing `PERF-` entries to avoid duplicates.

---

## Step 2 - Server/Client boundary checks (Explore agent)

Launch a **single Explore subagent** (model: haiku) with all page, component, and lib files from Step 1:

"Read `${CLAUDE_SKILL_DIR}/PATTERNS.md` for framework-specific grep patterns. Run all 9 checks below. For each: state total match count, list every match as `file:line - excerpt`, and state PASS or FAIL.

**CHECK B1 - Unnecessary client-side rendering scope**
Find components or pages marked for client-side rendering that do not actually use browser APIs (event handlers, state, refs, browser-only hooks). See PATTERNS.md → B1 for client-side directives per framework.
- Flag A: any client-marked file that uses NONE of: state management, event handlers, refs, or browser APIs. It may be renderable on the server.
- Flag B: any client-marked layout or provider file that imports 5+ child components - if only a small interactive portion requires client rendering, extracting it into an island would let the layout render on the server.

**CHECK B2 - Heavy libraries in client bundle**
Grep for imports of known-heavy libraries in client-rendered files. Flag any imports of libraries that do NOT need browser APIs and could run server-side:
- Document processing libraries (PDF, XLSX, etc.) - typically server-only
- Rich text editors - acceptable in client IF interactive; flag if read-only render
- Chart libraries - acceptable in client if interactive; flag if static data-display only
- Any library > ~50KB that has a server-side equivalent
Flag: each import with the library name and whether a server-side pattern exists.

**CHECK B3 - Client-side data fetching that defeats server rendering**
Find client-rendered components that fetch data in lifecycle hooks (see PATTERNS.md → B3) instead of using server-side data loading.
Flag: data fetching in client lifecycle hooks - these defeat server rendering and add a loading waterfall. Use server-side data loading with streaming/suspense, or a client-side cache library with proper revalidation.

**CHECK B4 - Unstable callback references defeating memoization**
Find inline arrow functions passed as props to memoized child components. Inline functions create new references on every parent render, defeating memoization.
Flag: each case. Skip native HTML element event handlers - frameworks batch these internally.

**CHECK B5 - Sequential await waterfall**
Pattern: two or more consecutive `await` calls for independent data sources in the same async function.
Grep in server-rendered files or API routes: lines matching `const .* = await` that appear consecutively (within 5 lines of each other) without the first result being an input to the second call.
Flag: each pair of sequential awaits that could be parallelised with `Promise.all` (or equivalent).
Example of violation: `const a = await getA(); const b = await getB();` where b doesn't depend on a.

**CHECK B6 - Missing caching on repeated server-side queries**
Find data fetches that run on every request without caching in server-rendered components.
Grep in server-rendered files for database query calls - check if they use any caching mechanism (framework cache, memoization, or explicit cache headers).
Flag: uncached queries in layout-level or frequently-visited components (e.g. navigation data, user profile). These execute on every page visit.

**CHECK B7 - Images without explicit dimensions (CLS risk)**
Find image elements (framework image component or native `<img>`) without width/height or fill/cover constraints.
Flag: each unsized image. Without dimensions, the browser cannot reserve layout space - content shifts when the image loads, causing CLS violations.

**CHECK B8 - Accidental dynamic rendering triggers**
Find patterns that force dynamic rendering at the layout level, opting entire route subtrees out of static generation:
- Request-scoped APIs (cookies, headers, session) called in layout files
- Explicit force-dynamic configuration in page/layout files
- No-cache directives in layout-level data fetches
Flag: each occurrence. Verify from context whether intentional (auth-dependent, real-time data) or avoidable with proper caching or component restructuring.

**CHECK B9 - Missing lazy loading for heavy client components**
Find imports of heavy libraries (rich text editors, chart libraries, complex UI components) that are statically imported without lazy loading.
Flag: any file where a heavy component is eagerly imported without using the framework's dynamic/lazy import mechanism (see PATTERNS.md → B9)."

---

## Step 3 - Bundle composition check (main context)

Read the framework configuration file.

**P1 - Bundle analyzer availability**
Check if a bundle analyzer is configured or available for the project's build tool (see PATTERNS.md → P1 for tool names per build system).
If no analyzer is configured or documented, flag as Medium - developers cannot easily audit bundle composition.

**P2 - Server-only package exclusion**
Check if the framework configuration excludes heavy server-only packages from the client bundle.
Identify packages in the project that should never be client-bundled (e.g. PDF processors, XLSX generators, database drivers, file system utilities).
Flag: any heavy server-only package not explicitly excluded from client bundling.

**P3 - Tree-shaking optimization for large libraries**
Check if the build configuration optimizes imports for large libraries with many exports where only a subset is used (e.g. icon libraries with hundreds of icons, utility libraries like lodash).
Note: some frameworks automatically optimize certain packages (check the framework docs). If a library is already auto-optimized by the build tool, note as PASS.
Flag: any package with 100+ exports where only a subset is used, not covered by the build tool's tree-shaking or import optimization.

---

## Step 4 - API query efficiency (Explore agent - separate pass)

"Run these 3 checks. Adapt grep patterns to the project's database client or ORM:

**CHECK Q1 - Unbounded queries (no limit on large-growth tables)**
Flag: each collection query without pagination bounds. Exception: export routes that intentionally fetch all for CSV/XLSX - verify from context.

**CHECK Q2 - Select * (over-fetching columns)**
Grep for select-all patterns in route handlers (see PATTERNS.md → Q2 for ORM-specific patterns).
Flag: each match. Fetching all columns is a performance and security risk - columns with large values are sent over the wire unnecessarily.

**CHECK Q3 - N+1 patterns**
Pattern A: database query calls inside `.map(`, `for`, or `forEach` loops.
Pattern B: sequential `await` with a DB client call inside a loop body.
Flag: each match. N+1 on a list endpoint means N DB queries for an N-item list - use batch queries or embedded/eager loading instead."

---

## Step 5 - Produce report and update backlog

Generate the report using the template in `${CLAUDE_SKILL_DIR}/REPORT.md` (Web Audit section). Apply the severity guide and backlog writing rules from the same file.

---

## Execution notes

- In `mode:audit` (default): do NOT make any code changes - report only. After producing the report, ask: "Should I implement the High/Critical priority optimisations?"
- In `mode:apply`: apply only the fixes listed in Quick wins (isolated, non-breaking). Describe each change before writing it. Do not apply Strategic refactors without explicit user confirmation. Do NOT ask the closing question - the user already expressed intent via `mode:apply`.
- Check CLAUDE.md "Known Patterns" for intentionally configured server-external packages, client-side component exclusions, or layout-level client directives before flagging them.

---

## Step 6 - Native/Backend Performance Audit

**This path runs for non-web projects only.** Web projects use Steps 1–5 above.

### Profiling tools

**Primary tool**: [PERF_TOOL]
**Profile command**: `[PROFILER_COMMAND]`

Run the profiler on the main execution path. Identify the top 5 hotspots by CPU time and the top 5 by memory allocation. If profiling data is not available, proceed with static analysis and recommend running the profiler.

---

### Step 6a - Algorithmic and resource checks (Explore agent)

Launch a **single Explore subagent** (model: haiku) with all source files from the project:

"Run these 4 checks on the provided source files. For each: state total match count, list every match as `file:line - excerpt`, and state PASS or FAIL.

**CHECK NP1 - Nested iteration on collections**
Grep for nested loops (for/while/map/forEach inside another loop body) operating on collections or arrays.
Flag: O(n²) or worse complexity. Exclude small fixed-size iterations (< 10 items known at compile time).

**CHECK NP2 - Memory allocation in hot paths**
Flag:
- Object/string/array/buffer creation inside loops (new allocation per iteration)
- Unbounded caches or collections that grow without eviction
- Missing cleanup of heavyweight resources (file handles, DB connections, network sockets)

**CHECK NP3 - I/O bottleneck patterns**
Flag:
- Synchronous file I/O on the main/UI thread
- Sequential network calls that could be parallelized
- Unbuffered reads/writes on large files
- Missing timeout on network or IPC operations

**CHECK NP4 - Concurrency inefficiency**
Flag:
- Thread/goroutine/task creation inside loops without pooling
- Shared mutable state without synchronization primitives
- Blocking calls on async/concurrent paths
- Missing cancellation support on long-running operations"

---

### Step 6b - Stack-specific checks (main context)

Read the 10 largest source files by line count. Apply the checks relevant to the project language using grep patterns from PATTERNS.md → Step 6b (organized by language). Run the patterns, then read flagged files for context.

---

### Step 6c - Resource footprint checks (main context)

**CHECK NR1 - Launch / startup weight**
Identify the application entry point (see PATTERNS.md → NR1 for per-language markers). Grep for heavy operations in the entry point: database initialization, network calls, large file reads, complex object graph construction. Flag any operation that could be deferred (lazy initialization) or moved to a background thread/task.

**CHECK NR2 - Memory management patterns**
Grep for per-language memory antipatterns from PATTERNS.md → NR2. Key categories: missing autorelease pools in batch loops, unbounded caches, leaked references, pre-allocation misses. Also flag large static/global collections that persist for the process lifetime.

**CHECK NR3 - Energy and background patterns** (mobile stacks only)
Grep for per-language energy antipatterns from PATTERNS.md → NR3. Key categories: tight timers without tolerance, high-frequency location updates, excessive wake-ups. Flag any background polling pattern that could use push notifications or event-driven updates instead.

**CHECK NR4 - Binary / artifact size**
- Grep for large embedded assets in source directories (images > 1MB, bundled databases, embedded fonts). Flag if assets could be downloaded on demand.
- Check for debug-only code or dependencies leaking into release builds.
- Grep for unused imports at module/package level - flag files importing modules they don't use.

---

### Step 6d - Produce report and update backlog

Generate the report using the template in `${CLAUDE_SKILL_DIR}/REPORT.md` (Native Audit section). Apply the severity guide and backlog writing rules from the same file.

---

### Native audit - execution notes

- In `mode:audit` (default): report only. After report, ask: "Should I implement the High/Critical priority optimisations?"
- In `mode:apply`: apply only Quick wins. Describe each change before writing.

Files in this skill

  • PATTERNS.md9.1 KB
  • REPORT.md8.3 KB
  • SKILL.md17.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.