Skip to content

Instantly share code, notes, and snippets.

@umeyuki
Created February 20, 2026 09:31
Show Gist options
  • Select an option

  • Save umeyuki/a398642eaadb4667aeda21be222cbd6e to your computer and use it in GitHub Desktop.

Select an option

Save umeyuki/a398642eaadb4667aeda21be222cbd6e to your computer and use it in GitHub Desktop.
[setup] knip + lefthook for TypeScript projects

knip + lefthook Setup for TypeScript Projects

Dead code detection + Git hooks in one setup. Works with: pnpm monorepo, SvelteKit, Hono, Vitest, Biome

1. Install

pnpm add -Dw knip lefthook

Add scripts to root package.json:

{
  "scripts": {
    "knip": "knip",
    "knip:fix": "knip --fix"
  }
}

2. knip.json

Single package

{
  "$schema": "https://unpkg.com/knip@5/schema.json"
}

knip auto-detects: package.json exports/main, tsconfig paths, Vitest tests, etc. Most single-package projects need zero config.

pnpm monorepo

{
  "$schema": "https://unpkg.com/knip@5/schema.json",
  "workspaces": {
    ".": {
      "entry": "scripts/*.ts"
    },
    "packages/*": {},
    "apps/backend": {
      "entry": "scripts/*.ts"
    },
    "apps/frontend": {}
  }
}
  • knip reads pnpm-workspace.yaml automatically
  • Built-in plugins: SvelteKit (+page.svelte, +server.ts), Vitest, Vite, etc.
  • "packages/*": {} — empty = rely on plugin auto-detection
  • Add "entry" only for non-standard entry points (e.g. scripts/)

Common suppressions

{
  // Files that are referenced but not directly imported (e.g. vitest setupFiles)
  "ignoreFiles": ["**/vitest.setup.ts"],

  // SvelteKit virtual modules (./$types) cause false "unresolved" reports
  "ignoreIssues": {
    "**/+server.ts": ["unresolved"],
    "**/+page.server.ts": ["unresolved"],
    "**/+layout.server.ts": ["unresolved"],
    "**/vitest.config.ts": ["unresolved"]
  }
}

Gotchas learned from real usage

Issue Cause Fix
./$types unresolved SvelteKit virtual module ignoreIssues on +server.ts etc.
vitest.setup.ts unused file Referenced via setupFiles, not import ignoreFiles
Workspace deps flagged unused .svelte-kit/ dir present Delete .svelte-kit/, rely on ignoreIssues instead
--fix removes needed dep Root scripts/*.ts not registered as entry Add ".": { "entry": "scripts/*.ts" }
Duplicate export warning export const X = Y where Y is already exported Add /** @alias */ JSDoc tag
--fix removes export but leaves dead local code knip only strips export keyword Manually delete the now-unused function

3. lefthook.yml

pre-commit:
  parallel: true
  jobs:
    - name: biome
      glob: "*.{ts,js,mjs,cjs}"
      run: pnpm biome check --no-errors-on-unmatched {staged_files}
    - name: knip
      run: pnpm knip --no-progress
  • biome: runs on staged files only (fast)
  • knip: analyzes entire project (dependency graph requires full scan)
  • parallel: true: both run concurrently
  • Do NOT add typecheck/test here (too slow for pre-commit)

ESLint + Prettier variant (non-Biome projects)

pre-commit:
  parallel: true
  jobs:
    - name: lint
      glob: "*.{ts,js,mjs,cjs,tsx,jsx}"
      run: pnpm eslint --no-warn-ignored {staged_files}
    - name: format
      glob: "*.{ts,js,mjs,cjs,tsx,jsx,json,css,md}"
      run: pnpm prettier --check {staged_files}
    - name: knip
      run: pnpm knip --no-progress

4. .gitignore

# lefthook
lefthook-local.yml

5. Activate & Verify

# Install git hooks
pnpm lefthook install

# Run knip standalone
pnpm knip

# Auto-fix (removes unused exports/deps)
pnpm knip --fix

# Test hooks manually
pnpm lefthook run pre-commit

# Verify no breakage
pnpm build && pnpm test && pnpm typecheck

6. CI integration (optional)

# GitHub Actions
- name: Dead code check
  run: pnpm knip --no-progress

Quick reference

pnpm knip                  # Detect issues
pnpm knip --fix            # Auto-remove unused exports/deps
pnpm knip --include files  # Only check unused files
pnpm knip --include exports # Only check unused exports
pnpm knip --debug          # Verbose output for troubleshooting config
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment