Skip to main content
hook

performance-budget-guard — Claude Code hook: bundle size and deploy

A Claude hook that measures your Next.js JS bundle after a build and blocks the deploy when it goes over the performance budget.

Install into Claude Code · claude-code-templates All methods and platforms ↓
npx claude-code-templates@latest --hook performance/performance-budget-guard
Open on GitHub

What performance-budget-guard does

The hook fires on PostToolUse after npm run build, next build, vercel build or yarn build. On a successful build it sums every .js file under .next/static/chunks and compares the total against a 350KB limit. Under budget, it prints the headroom and warns when less than 50KB is left. Over budget, you get the overage, the five heaviest chunks and a list of suggestions, then the script exits with code 2 — the deploy does not go through.

The second trigger covers file edits through Write, Edit and MultiEdit. It looks at .js, .jsx, .ts and .tsx outside node_modules and flags things as you type: a file over 100KB, more than 15 imports, a wildcard import, a full lodash import instead of a per-function one, moment anywhere in the file. Those are notes, not blocks.

One thing to know before you install: the 350KB limit is hardcoded in the script, there is no per-project setting. The size check also depends on a .next directory, so a build that does not produce one gets a message that the folder is missing. The script uses the macOS stat form with a GNU fallback, so it runs on Linux and in CI as well.

What it helps with

  • catch a bloated bundle right after the build instead of in production
  • stop a deploy that pushes JS past the budget
  • list the heaviest chunks under .next/static/chunks
  • spot a full lodash or moment import in a file you just edited
  • see when less than 50KB of budget is left

Example prompts for the agent

  • build the project and tell me whether we are still inside the bundle budget
  • check that my edit to app/page.tsx did not pull in heavy imports
  • run npm run build and break down which chunks are the largest

How to install performance-budget-guard

1claude-code-templates

npx claude-code-templates@latest --hook performance/performance-budget-guard

2Manually: put the files in place

.claude/settings.json

The hooks block: event (PreToolUse, PostToolUse, Stop…) → command. Personal ones go to ~/.claude/settings.json

Step by step, with commands for each platform: Claude Code hooks: what they are, where to configure them, how to block a risky command

Questions about performance-budget-guard

How do I install performance-budget-guard in Claude?

Run npx claude-code-templates@latest --hook performance/performance-budget-guard, then check the entry in .claude/settings.json.

What does performance-budget-guard do?

It measures the JS bundle after a Next.js build and compares it to a 350KB limit. When you go over, it prints a report and blocks the deploy.

When does the hook run?

On PostToolUse for npm run build, next build, vercel build and yarn build, and for edits to .js, .jsx, .ts and .tsx files made with Write, Edit or MultiEdit.

Source text

performance-budget-guard.json · MIT
{
  "description": "Monitor bundle size and Core Web Vitals metrics during development, blocking deployments that exceed performance budgets with detailed reports. Automatically analyzes Next.js build output, checks bundle sizes against predefined budgets, and provides optimization recommendations. Hook triggers on PostToolUse for build-related operations and file changes that could affect performance.",
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'input=$(cat); COMMAND=$(echo \"$input\" | jq -r \".tool_input.command // empty\"); SUCCESS=$(echo \"$input\" | jq -r \".tool_response.success // false\"); if [ \"$SUCCESS\" = \"true\" ] && [[ \"$COMMAND\" =~ (npm\\ run\\ build|next\\ build|vercel\\ build|yarn\\ build) ]]; then echo \"📊 Performance Budget Guard: Analyzing build output...\"; if [ -d \".next\" ]; then BUNDLE_SIZE=$(find .next/static/chunks -name \"*.js\" -exec stat -f%z {} + 2>/dev/null | awk \"{total += \\$1} END {print total}\"); BUNDLE_SIZE_KB=$((BUNDLE_SIZE / 1024)); BUDGET_LIMIT=350; echo \"📦 Total bundle size: ${BUNDLE_SIZE_KB}KB\"; if [ $BUNDLE_SIZE_KB -gt $BUDGET_LIMIT ]; then echo \"🚨 PERFORMANCE BUDGET EXCEEDED!\"; echo \"Current bundle size: ${BUNDLE_SIZE_KB}KB\"; echo \"Budget limit: ${BUDGET_LIMIT}KB\"; echo \"Overage: $((BUNDLE_SIZE_KB - BUDGET_LIMIT))KB\"; echo \"\" >&2; echo \"⚠️ Performance budget exceeded by $((BUNDLE_SIZE_KB - BUDGET_LIMIT))KB!\" >&2; echo \"\" >&2; echo \"📋 Bundle Analysis:\" >&2; find .next/static/chunks -name \"*.js\" -exec ls -lah {} + 2>/dev/null | sort -k5 -hr | head -5 >&2; echo \"\" >&2; echo \"💡 Optimization recommendations:\" >&2; echo \"• Use dynamic imports for large components\" >&2; echo \"• Implement code splitting with next/dynamic\" >&2; echo \"• Check for duplicate dependencies\" >&2; echo \"• Optimize third-party libraries\" >&2; echo \"• Run: npm run analyze for detailed bundle analysis\" >&2; exit 2; else echo \"✅ Bundle size within budget: ${BUNDLE_SIZE_KB}KB / ${BUDGET_LIMIT}KB\"; REMAINING=$((BUDGET_LIMIT - BUNDLE_SIZE_KB)); echo \"🎯 Remaining budget: ${REMAINING}KB\"; if [ $REMAINING -lt 50 ]; then echo \"⚠️ Warning: Less than 50KB remaining in performance budget\"; fi; fi; else echo \"❌ No .next build directory found. Run build first.\"; fi; else echo \"ℹ️ Performance check skipped (not a build command or failed build)\"; fi'",
            "timeout": 30
          }
        ]
      },
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'input=$(cat); FILE_PATH=$(echo \"$input\" | jq -r \".tool_input.file_path // empty\"); SUCCESS=$(echo \"$input\" | jq -r \".tool_response.success // false\"); if [ \"$SUCCESS\" = \"true\" ] && [[ \"$FILE_PATH\" =~ \\.(js|jsx|ts|tsx)$ ]] && [[ ! \"$FILE_PATH\" =~ node_modules ]]; then echo \"🔍 Performance Guard: Checking code changes in $FILE_PATH...\"; if [ -f \"$FILE_PATH\" ]; then FILE_SIZE=$(stat -f%z \"$FILE_PATH\" 2>/dev/null || stat -c%s \"$FILE_PATH\" 2>/dev/null); FILE_SIZE_KB=$((FILE_SIZE / 1024)); if [ $FILE_SIZE_KB -gt 100 ]; then echo \"⚠️ Large file detected: ${FILE_SIZE_KB}KB\"; echo \"💡 Consider splitting large components or lazy loading\"; fi; IMPORTS_COUNT=$(grep -c \"^import\" \"$FILE_PATH\" 2>/dev/null || echo \"0\"); if [ $IMPORTS_COUNT -gt 15 ]; then echo \"📦 Many imports detected: $IMPORTS_COUNT imports\"; echo \"💡 Consider consolidating imports or tree-shaking unused code\"; fi; if grep -q \"import.*\\*.*from\" \"$FILE_PATH\" 2>/dev/null; then echo \"🚨 Wildcard import detected in $FILE_PATH\"; echo \"💡 Use specific imports instead of wildcard imports for better tree-shaking\"; fi; if grep -q \"moment\" \"$FILE_PATH\" 2>/dev/null; then echo \"📅 Moment.js usage detected\"; echo \"💡 Consider using date-fns or native Date for smaller bundle size\"; fi; if grep -q \"lodash\" \"$FILE_PATH\" 2>/dev/null && ! grep -q \"lodash/\" \"$FILE_PATH\" 2>/dev/null; then echo \"🔧 Full Lodash import detected\"; echo \"💡 Use specific Lodash functions: import debounce from \\\"lodash/debounce\\\"\"; fi; echo \"✅ Performance check completed for $FILE_PATH\"; else echo \"❌ File $FILE_PATH not found\"; fi; else echo \"ℹ️ Performance check skipped (not a JavaScript/TypeScript file or failed operation)\"; fi'",
            "timeout": 15
          }
        ]
      }
    ]
  }
}

© davila7 · MIT · davila7/claude-code-templates

Similar hooks

Everything for Frontend and UI →

From the same set205

The whole set →
optimize-database-performance A Claude slash command that walks through slow queries, indexes and schema, then tells you what to rewrite. Useful when a page stalls on one SELECT. 794installs doc-api Scans your codebase for endpoints and writes the API documentation: spec, request and response examples, an interactive page. Useful when there are too many routes to describe by hand. 733installs performance-audit Audits codebase performance, locating slow database queries, nested loops, and build bottlenecks. Prioritizes optimizations by system impact and implementation effort. 661installs setup-development-environment A slash command that builds out a dev environment: runtimes, tooling, build setup, linters, configs. Handy when you spin up a project on a fresh machine. 651installs vercel-environment-sync A hook that inspects environment variables after an .env edit and points you to the right Vercel sync commands. Useful when local and deployed values drift apart. 363installs env-file-protection This hook stops Write calls aimed at .env* files, so an agent cannot overwrite your secrets by accident. One command adds it to Claude settings. 279installs slack-notifications Posts a Slack message when Claude finishes working or a subagent completes its task. Useful when you step away from the terminal and want to know the run is done. 279installs discord-notifications Posts a Discord message when Claude stops working or a subagent finishes. Useful when you step away from the terminal and want a ping on completion. 217installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor