vercel-doctor
v1.2.0
Published
Find ways to cut your Vercel bill (Next.js)
Maintainers
Readme
Reduce your Vercel bill with one command.
Scans your Next.js codebase for patterns that increase your Vercel bill — long function durations, uncached routes, unoptimized images, expensive cron jobs, and more — then outputs actionable diagnostics.
See it in action →
https://github.com/user-attachments/assets/e03596de-4b68-4a3e-8623-51c765647b26
How it works
Vercel Doctor detects your framework and project setup, then runs two analysis passes in parallel:
- Billing lint — detects patterns that inflate your Vercel invoice:
- Function duration: sequential
awaits, blockingafter()calls, side effects in GET handlers - Caching: missing cache policies,
force-dynamic/no-storeoverrides, SSR where SSG would work - Image optimization: global image optimization disabled, next/image with SVG without
unoptimized, overly broad remote patterns, missingsizesprop - Invocations: Link prefetch default (use
prefetch={false}or disable globally, then addprefetch={true}only to critical links) - Edge functions: heavy imports, sequential awaits that burn CPU time
- Version-aware handling: Next.js 15/16+ caching guidance tailored to your detected Next.js major version
- Static assets: large files that should be served from an external CDN
- Build optimization: Turbopack build cache (Next.js 16+),
getStaticPropswithoutrevalidate(consider ISR), large projects →vercel deploy --archive=tgz - Platform usage: Vercel Cron vs. GitHub Actions / Cloudflare Workers, Fluid Compute, Bun runtime
- Function duration: sequential
- Dead code — detects unused files, exports, types, and duplicates that slow cold starts.
Diagnostics are filtered through your config to produce actionable results.
Install
Run this at your project root:
npx -y vercel-doctor@latest .Use --verbose to see affected files and line numbers:
npx -y vercel-doctor@latest . --verboseInstall for your coding agent
Teach your coding agent Vercel cost optimization rules:
curl -fsSL https://vercel-doctor.com/install-skill.sh | bashSupports Cursor, Claude Code, Amp Code, Codex, Gemini CLI, OpenCode, Windsurf, and Antigravity.
Options
Usage: vercel-doctor [directory] [options]
Options:
-v, --version display the version number
--no-lint skip linting
--no-dead-code skip dead code detection
--verbose show file details per rule
--score output only the score
-y, --yes skip prompts, scan all workspace projects
--project <name> select workspace project (comma-separated for multiple)
--diff [base] scan only files changed vs base branch
--offline skip telemetry (anonymous, not stored, only used to calculate score)
--output <format> output format: "human" (default), "json", or "markdown"
--report <file> write human-readable report to file
--ai-prompts <file> write AI fix prompts to JSON file for use with Cursor/Claude/Windsurf
-h, --help display help for commandConfiguration
Create a vercel-doctor.config.json in your project root to customize behavior:
{
"ignore": {
"rules": ["vercel-doctor/nextjs-image-missing-sizes", "knip/exports"],
"files": ["src/generated/**"]
}
}You can also use the "vercelDoctor" key in your package.json instead:
{
"vercelDoctor": {
"ignore": {
"rules": ["vercel-doctor/nextjs-image-missing-sizes"]
}
}
}If both exist, vercel-doctor.config.json takes precedence.
Config options
| Key | Type | Default | Description |
| -------------- | ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| ignore.rules | string[] | [] | Rules to suppress, using the plugin/rule format shown in diagnostic output (e.g. vercel-doctor/async-parallel, knip/exports) |
| ignore.files | string[] | [] | File paths to exclude, supports glob patterns (src/generated/**, **/*.test.tsx) |
| lint | boolean | true | Enable/disable lint checks (same as --no-lint) |
| deadCode | boolean | true | Enable/disable dead code detection (same as --no-dead-code) |
| verbose | boolean | false | Show file details per rule (same as --verbose) |
| diff | boolean \| string | — | Force diff mode (true) or pin a base branch ("main"). Set to false to disable auto-detection. |
CLI flags always override config values.
Report Generation & AI Prompts
Generate detailed reports and AI-compatible fix prompts:
# Generate a markdown report
npx vercel-doctor . --output markdown --report report.md
# Export AI prompts for fixing issues (use with Cursor, Claude, Windsurf)
npx vercel-doctor . --ai-prompts fixes.jsonThe --ai-prompts flag generates ready-to-use prompts for AI coding tools. It only exports issues that have a known fix strategy. The format is auto-detected from the file extension:
.json- Structured format for programmatic use and automation.mdor.markdown- Human-readable format, easy to copy-paste into AI chats
# Export as JSON (for scripts, automation)
npx vercel-doctor . --ai-prompts fixes.json
# Export as Markdown (for manual copy-paste into Cursor/Claude/Windsurf)
npx vercel-doctor . --ai-prompts fixes.mdEach prompt includes:
- The specific rule violation
- File location, line, and column number
- Before/after code examples
- Step-by-step fix instructions
Example AI prompt output:
{
"vercel-doctor/vercel-no-force-dynamic::src/app/page.tsx:15:1": "Fix this Vercel optimization issue..."
}Node.js API
You can also use Vercel Doctor programmatically:
import { diagnose } from "vercel-doctor/api";
const result = await diagnose("./path/to/your/nextjs-project");
console.log(result.score); // { score: 82, label: "Good" } or null
console.log(result.diagnostics); // Array of Diagnostic objects
console.log(result.project); // Detected framework, React version, etc.The diagnose function accepts an optional second argument:
const result = await diagnose(".", {
lint: true, // run lint checks (default: true)
deadCode: true, // run dead code detection (default: true)
});Each diagnostic has the following shape:
interface Diagnostic {
filePath: string;
plugin: string;
rule: string;
severity: "error" | "warning";
message: string;
help: string;
line: number;
column: number;
category: string;
}Contributing
Want to contribute? Check out the codebase and submit a PR.
git clone https://github.com/Aniket-508/vercel-doctor
cd vercel-doctor
pnpm install
pnpm -r run buildRun locally:
node packages/vercel-doctor/dist/cli.js /path/to/your/nextjs-project