
Build Optimization
- 39 installs
- 28 repo stars
- Updated June 29, 2026
- nickcrew/claude-ctx-plugin
Helps with ai & agent building tasks.
About
build-optimization is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- build-optimization
- AI & Agent Building
- AI-coding skill
Build Optimization by the numbers
- 39 all-time installs (skills.sh)
- Ranked #8,260 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/nickcrew/claude-ctx-plugin --skill build-optimizationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 39 |
|---|---|
| repo stars | ★ 28 |
| Last updated | June 29, 2026 |
| Repository | nickcrew/claude-ctx-plugin ↗ |
What it does
Helps with ai & agent building tasks.
Files
Build Optimization
Expert guidance for optimizing build systems, reducing compilation times, maximizing cache hit rates, and building developer tools that enhance productivity across the development lifecycle.
When to Use This Skill
- Diagnosing slow build times and identifying bottlenecks
- Configuring caching strategies (local, remote, distributed)
- Setting up incremental builds and parallel execution
- Optimizing CI/CD pipeline performance and cost
- Designing or improving bundle splitting and tree shaking
- Building CLIs, plugins, code generators, or IDE extensions
- Configuring monorepo tooling (Nx, Turborepo, Bazel)
- Reducing developer feedback loop times (hot reload, watch mode)
- Managing build artifacts and reproducibility
Quick Reference
| Task | Load reference |
|---|---|
| Compilation, caching, incremental builds, CI/CD optimization | skills/build-optimization/references/build-systems.md |
| Plugin systems, code generation, linting, IDE integration, monorepo tooling | skills/build-optimization/references/developer-tooling.md |
Core Targets
- Build time under 30 seconds for development builds
- Rebuild time under 5 seconds with watch mode
- Cache hit rate above 90% in CI
- Zero flaky builds in production pipelines
- Reproducible builds across environments
Workflow
1. Performance Analysis
Profile the current build before making changes.
- Measure cold build, incremental rebuild, and hot reload times
- Profile CPU, memory, and I/O during builds
- Map the dependency graph and identify bottlenecks
- Evaluate cache hit rates and invalidation patterns
- Review current tool configuration for missed optimizations
2. Optimization
Apply targeted improvements based on profiling data.
- Enable incremental compilation and caching
- Configure parallel execution across available cores
- Set up code splitting and tree shaking
- Optimize module resolution and source transformation
- Implement remote or distributed caching for CI
3. Tooling
Build or configure developer tools for fast feedback loops.
- Configure watch mode and hot module replacement
- Set up clear error messages and progress indicators
- Integrate build analytics and performance dashboards
- Add pre-commit hooks for format, lint, and validation
4. Monitoring
Track build health over time.
- Set up automated build time tracking and alerting
- Monitor cache hit rates and bundle size trends
- Detect performance regressions in CI
- Review and optimize periodically based on data
Common Mistakes
- Optimizing without profiling first
- Disabling caching due to intermittent issues instead of fixing invalidation
- Running full builds when incremental builds would suffice
- Not parallelizing independent build tasks
- Ignoring I/O as a bottleneck (disk speed, network latency)
- Letting bundle sizes grow unchecked without analysis
- Using a single build configuration for development and production
Build Systems
Compilation Optimization
Incremental Compilation
Only recompile files that have changed or depend on changed files:
// tsconfig.json - enable incremental TypeScript compilation
{
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": ".tsbuildinfo",
"composite": true
}
}Key principle: Track file hashes and dependency edges. If a file's hash is unchanged and none of its dependencies changed, skip recompilation.
Parallel Processing
Use all available CPU cores during compilation:
// webpack.config.js - parallel loaders
module.exports = {
module: {
rules: [{
test: /\.tsx?$/,
use: [
{
loader: 'thread-loader',
options: { workers: require('os').cpus().length - 1 }
},
'ts-loader'
]
}]
}
};# esbuild - inherently parallel
esbuild src/index.ts --bundle --outdir=dist --minify
# tsc with project references for parallel compilation
tsc --build --verbose # builds projects in dependency order, parallelizes independent onesModule Resolution Optimization
Reduce the cost of finding modules:
// webpack.config.js
module.exports = {
resolve: {
// limit search paths
modules: [path.resolve('./src'), 'node_modules'],
// specify extensions to try (avoid unnecessary file system calls)
extensions: ['.ts', '.tsx', '.js'],
// use package.json "exports" field
conditionNames: ['import', 'module', 'default'],
// alias to avoid deep resolution
alias: { '@': path.resolve('./src') }
}
};Type Checking Optimization
Separate type checking from compilation:
# compile with esbuild (fast, no type checking)
esbuild src/index.ts --bundle --outdir=dist
# type check separately (can run in parallel)
tsc --noEmit --incrementalDead Code Elimination
// webpack production config
module.exports = {
mode: 'production', // enables tree shaking
optimization: {
usedExports: true, // mark unused exports
minimize: true, // remove dead code
sideEffects: true, // respect package.json sideEffects field
concatenateModules: true // scope hoisting
}
};---
Caching Strategies
Local Filesystem Cache
// webpack 5 persistent cache
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename], // invalidate when config changes
},
cacheDirectory: path.resolve('.cache/webpack'),
compression: 'gzip',
}
};# Vite - uses filesystem cache by default
# Cache stored in node_modules/.viteRemote Cache
Share build artifacts across CI runs and developers:
// turbo.json - Turborepo remote cache
{
"remoteCache": {
"enabled": true
}
}# Turborepo remote cache setup
npx turbo login
npx turbo link
# Nx remote cache
nx connect-to-nx-cloudDistributed Cache
# Bazel remote cache configuration
build --remote_cache=grpcs://cache.example.com
build --remote_upload_local_results=true
build --remote_timeout=30Content-Based Hashing
Hash inputs to determine if outputs can be reused:
Input hash = hash(source files + config + dependency versions + environment)
If cache[input_hash] exists → reuse cached output
Else → build and store result in cache[input_hash]Cache Invalidation Rules
| Change Type | Invalidation Scope |
|---|---|
| Source file modified | That file + downstream dependents |
| Config file changed | Full rebuild for affected scope |
| Dependency version bumped | Modules importing that dependency |
| Node.js version changed | Full rebuild |
| Environment variable changed | Tasks using that variable |
---
Incremental Build Patterns
File Watching
// webpack watch mode
module.exports = {
watch: true,
watchOptions: {
ignored: /node_modules/,
aggregateTimeout: 200, // batch changes within 200ms
poll: false // use native file system events
}
};Hot Module Replacement (HMR)
Replace modules in a running application without full reload:
// Vite HMR - built in
// vite.config.ts
export default defineConfig({
server: {
hmr: {
overlay: true // show errors as overlay
}
}
});Affected Detection in Monorepos
Only rebuild packages affected by changes:
# Turborepo - run only affected tasks
turbo run build --filter=...[HEAD~1]
# Nx - affected detection
nx affected --target=build --base=main --head=HEAD
# Bazel - query affected targets
bazel query "rdeps(//..., set($(git diff --name-only HEAD~1)))"---
Parallel Execution
Task-Level Parallelism
// turbo.json - define task dependencies for parallel execution
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": []
},
"lint": {
"outputs": []
}
}
}With this config, lint runs in parallel with build since they have no dependency. test waits for build.
Process-Level Parallelism
# npm-run-all for parallel scripts
npx npm-run-all --parallel lint typecheck test:unit
# GNU parallel for arbitrary commands
find packages -name "package.json" -maxdepth 2 | parallel "cd {//} && npm run build"---
Dependency Management
Lock Files
Always commit lock files for reproducible builds:
| Package Manager | Lock File |
|---|---|
| npm | package-lock.json |
| yarn | yarn.lock |
| pnpm | pnpm-lock.yaml |
| bun | bun.lock |
Dependency Deduplication
# npm - dedupe nested dependencies
npm dedupe
# yarn - dedupe
yarn dedupe
# pnpm - strict by default (hoisting disabled)
# uses content-addressable storage to share dependenciesPhantom Dependencies
In monorepos, prevent packages from importing undeclared dependencies:
# .npmrc for pnpm strict mode
strict-peer-dependencies=true
auto-install-peers=false---
Build Reproducibility
Deterministic Builds
// webpack - consistent output ordering
module.exports = {
optimization: {
moduleIds: 'deterministic', // stable module IDs
chunkIds: 'deterministic', // stable chunk IDs
},
output: {
hashFunction: 'xxhash64', // fast, deterministic hashing
}
};Environment Isolation
# Dockerfile for reproducible builds
FROM node:20-slim AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts # deterministic install
COPY . .
RUN npm run build---
CI/CD Pipeline Optimization
Dependency Caching in CI
# GitHub Actions - cache node_modules
- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
node_modules
.cache
key: deps-${{ hashFiles('package-lock.json') }}
restore-keys: deps-Parallel CI Jobs
# GitHub Actions - parallel test matrix
jobs:
test:
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- run: npm test -- --shard=${{ matrix.shard }}/4Build Artifact Management
# upload build artifacts for downstream jobs
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
retention-days: 7
# download in deployment job
- uses: actions/download-artifact@v4
with:
name: build-output
path: dist/Pipeline Speed Tips
1. Cache aggressively: Dependencies, build outputs, test fixtures 2. Run independent jobs in parallel: Lint, typecheck, and unit tests don't depend on each other 3. Use sharding: Split test suites across multiple runners 4. Skip unnecessary work: Use path filters to skip unchanged packages 5. Use faster runners: Self-hosted runners with SSDs and more cores 6. Minimize Docker layers: Order Dockerfile commands by change frequency
---
Artifact Management
Content-Addressed Storage
# store artifacts by content hash
HASH=$(sha256sum dist/bundle.js | cut -d' ' -f1)
aws s3 cp dist/bundle.js s3://artifacts/${HASH}/bundle.js
# retrieve by hash
aws s3 cp s3://artifacts/${HASH}/bundle.js dist/bundle.jsBundle Analysis
# webpack bundle analyzer
npx webpack-bundle-analyzer dist/stats.json
# source-map-explorer for any bundler
npx source-map-explorer dist/bundle.js
# Vite bundle analysis
npx vite-bundle-visualizerTrack bundle size in CI to prevent regressions:
# bundlesize - fail CI if bundle exceeds threshold
npx bundlesize --max-size 250kB --files dist/main.*.jsDeveloper Tooling
Plugin System Design
Hook-Based Architecture
Plugins register callbacks for lifecycle events:
interface Plugin {
name: string;
setup(hooks: PluginHooks): void;
}
interface PluginHooks {
beforeBuild: AsyncHook<BuildConfig>;
afterBuild: AsyncHook<BuildResult>;
onError: AsyncHook<BuildError>;
transform: AsyncHook<{ code: string; id: string }>;
}
// example plugin
const timingPlugin: Plugin = {
name: 'timing',
setup(hooks) {
let start: number;
hooks.beforeBuild.tap(() => { start = Date.now(); });
hooks.afterBuild.tap((result) => {
console.log(`Build completed in ${Date.now() - start}ms`);
});
}
};Middleware Pattern
Chain transformations through composable functions:
type Middleware = (ctx: Context, next: () => Promise<void>) => Promise<void>;
class Pipeline {
private middlewares: Middleware[] = [];
use(fn: Middleware) {
this.middlewares.push(fn);
return this;
}
async execute(ctx: Context) {
let index = 0;
const next = async () => {
if (index < this.middlewares.length) {
await this.middlewares[index++](ctx, next);
}
};
await next();
}
}
// usage
pipeline
.use(loggingMiddleware)
.use(cachingMiddleware)
.use(transformMiddleware);Plugin API Stability
- Version your plugin API with semver
- Document which hooks are stable vs. experimental
- Provide migration guides when changing hook signatures
- Use TypeScript interfaces to define the plugin contract
---
Code Generation Patterns
Template-Based Generation
// template-based code generator
import Handlebars from 'handlebars';
const componentTemplate = Handlebars.compile(`
import React from 'react';
interface {{name}}Props {
{{#each props}}
{{this.name}}: {{this.type}};
{{/each}}
}
export function {{name}}({ {{propNames}} }: {{name}}Props) {
return (
<div className="{{kebabCase name}}">
{/* TODO: implement */}
</div>
);
}
`);
function generateComponent(name: string, props: Prop[]) {
return componentTemplate({
name,
props,
propNames: props.map(p => p.name).join(', '),
});
}AST Manipulation
Transform code structurally rather than textually:
import * as ts from 'typescript';
function addLogging(sourceFile: ts.SourceFile): ts.SourceFile {
const transformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
return (node) => {
function visit(node: ts.Node): ts.Node {
if (ts.isFunctionDeclaration(node) && node.name) {
// inject console.log at the start of every function
const logStatement = ts.factory.createExpressionStatement(
ts.factory.createCallExpression(
ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier('console'),
'log'
),
undefined,
[ts.factory.createStringLiteral(`Entering ${node.name.text}`)]
)
);
return ts.factory.updateFunctionDeclaration(
node, node.modifiers, node.asteriskToken, node.name,
node.typeParameters, node.parameters, node.type,
ts.factory.createBlock([logStatement, ...node.body!.statements])
);
}
return ts.visitEachChild(node, visit, context);
}
return ts.visitNode(node, visit) as ts.SourceFile;
};
};
const result = ts.transform(sourceFile, [transformer]);
return result.transformed[0];
}Schema-Driven Generation
Generate code from OpenAPI, GraphQL, or JSON Schema:
# OpenAPI to TypeScript
npx openapi-typescript api/openapi.yaml -o src/types/api.ts
# GraphQL codegen
npx graphql-codegen --config codegen.yml
# JSON Schema to TypeScript
npx json2ts -i schemas/ -o src/types/Type Generation
Generate types from runtime data or external sources:
# Prisma - generate types from database schema
npx prisma generate
# tRPC - infer types from API routes (no generation needed)
# Zod - infer TypeScript types from validation schemas
type User = z.infer<typeof userSchema>;---
Linting and Formatting Configuration
ESLint Setup
// eslint.config.js (flat config)
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
}],
}
},
{
ignores: ['dist/', 'node_modules/', 'coverage/'],
}
);Prettier Integration
// .prettierrc
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2
}# avoid ESLint and Prettier conflicts
npm install -D eslint-config-prettier
# run both efficiently
npx prettier --check .
npx eslint .Pre-Commit Hooks
# install husky + lint-staged
npm install -D husky lint-staged
npx husky init// package.json
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yml}": ["prettier --write"]
}
}---
IDE Integration
VS Code Settings for Build Tools
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.tsdk": "node_modules/typescript/lib",
"search.exclude": {
"dist": true,
"node_modules": true,
".cache": true
}
}VS Code Tasks
// .vscode/tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "Build",
"type": "npm",
"script": "build",
"group": { "kind": "build", "isDefault": true },
"problemMatcher": ["$tsc"]
},
{
"label": "Test",
"type": "npm",
"script": "test",
"group": { "kind": "test", "isDefault": true }
}
]
}Language Server Protocol (LSP)
Key capabilities for custom tools:
- Diagnostics (errors, warnings in editor)
- Completions (autocomplete suggestions)
- Hover information (documentation on hover)
- Go to definition / find references
- Code actions (quick fixes, refactoring)
---
Task Runner Patterns
npm Scripts Organization
{
"scripts": {
"build": "tsc && vite build",
"build:watch": "tsc --watch & vite build --watch",
"dev": "vite",
"lint": "eslint . && prettier --check .",
"lint:fix": "eslint --fix . && prettier --write .",
"test": "vitest",
"test:ci": "vitest run --coverage",
"typecheck": "tsc --noEmit",
"validate": "npm-run-all --parallel lint typecheck test:ci"
}
}Makefile for Polyglot Projects
.PHONY: build test lint clean
build: node_modules
npm run build
test: node_modules
npm run test:ci
lint: node_modules
npm run lint
clean:
rm -rf dist node_modules/.cache
node_modules: package-lock.json
npm ci
touch node_modules # update timestamp for make---
Dependency Update Automation
Renovate Configuration
// renovate.json
{
"extends": ["config:base"],
"schedule": ["before 8am on Monday"],
"automerge": true,
"automergeType": "branch",
"packageRules": [
{
"matchUpdateTypes": ["patch", "minor"],
"automerge": true
},
{
"matchUpdateTypes": ["major"],
"automerge": false,
"labels": ["breaking-change"]
},
{
"matchDepTypes": ["devDependencies"],
"automerge": true
}
]
}Dependabot Configuration
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
open-pull-requests-limit: 10
groups:
dev-dependencies:
dependency-type: development
update-types: [minor, patch]
production-dependencies:
dependency-type: production---
Monorepo Tooling
Turborepo
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [".env"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}Key features: Remote caching, task parallelism, affected filtering.
Nx
// nx.json
{
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"cache": true
},
"test": {
"cache": true
}
},
"namedInputs": {
"default": ["{projectRoot}/**/*"],
"production": ["default", "!{projectRoot}/**/*.spec.*"]
}
}Key features: Computation caching, affected detection, project graph visualization, code generators.
Bazel
# BUILD file
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")
ts_project(
name = "lib",
srcs = glob(["src/**/*.ts"]),
deps = ["//:node_modules/@types/node"],
declaration = True,
tsconfig = ":tsconfig",
)Key features: Hermetic builds, content-addressable cache, distributed execution, language-agnostic.
Choosing a Monorepo Tool
| Factor | Turborepo | Nx | Bazel |
|---|---|---|---|
| Setup complexity | Low | Medium | High |
| Caching | Remote cache | Nx Cloud | Remote execution |
| Language support | JS/TS focused | JS/TS + plugins | Any language |
| Affected detection | Git-based | Project graph | Query language |
| Best for | JS/TS monorepos | Enterprise JS/TS | Large polyglot repos |