--- title: no-banned-api description: Ban specific runtime APIs that cause cross-platform or reliability issues and enforce safe alternatives. --- Ban specific runtime APIs that cause cross-platform or reliability issues. ## Rule details Some APIs work correctly on one platform but fail on another. For example, Bun's shell API (`Bun.$`) hangs on Windows due to pipe deadlocks. This rule detects multiple variants of a banned API — the direct call, the import, and destructured usage — ensuring no form slips through. This pattern generalizes to any API you want to ban while allowing a safe alternative. ## Examples of **incorrect** code ```typescript title="src/helpers/git.ts" // Direct usage const result = await Bun.$`git status`; // Import import { $ } from "bun"; // Destructured usage const output = await $`ls -la`; ``` ## Examples of **correct** code ```typescript title="src/helpers/git.ts" const proc = Bun.spawn(["git", "status"], { stdout: "pipe", stderr: "pipe" }); const output = await new Response(proc.stdout).text(); ``` ## Rule implementation ```typescript /// export default { rules: { "no-bun-shell": { description: "Subprocess execution must use Bun.spawn, not Bun.$ (shell hangs on Windows)", async check(ctx) { const files = ctx.scopedFiles.filter( (f) => !f.includes("tests/") && !f.includes(".archgate/") ); // Variant 1: Bun.$` template literal const bunShellMatches = await Promise.all( files.map((file) => ctx.grep(file, /Bun\.\$`/)) ); for (const fileMatches of bunShellMatches) { for (const m of fileMatches) { ctx.report.violation({ message: "Do not use Bun.$ template literals — they hang on Windows. Use Bun.spawn instead.", file: m.file, line: m.line, fix: "Replace Bun.$`cmd args` with Bun.spawn(['cmd', 'args'], { stdout: 'pipe', stderr: 'pipe' })", }); } } // Variant 2: import { $ } from "bun" const dollarImportMatches = await Promise.all( files.map((file) => ctx.grep(file, /import\s*\{[^}]*\$[^}]*\}\s*from\s*["']bun["']/) ) ); for (const fileMatches of dollarImportMatches) { for (const m of fileMatches) { ctx.report.violation({ message: 'Do not import $ from "bun" — the shell API hangs on Windows. Use Bun.spawn instead.', file: m.file, line: m.line, fix: "Remove the $ import and replace shell calls with Bun.spawn", }); } } // Variant 3: await $` (destructured) const destructuredMatches = await Promise.all( files.map((file) => ctx.grep(file, /await\s+\$`/)) ); for (const fileMatches of destructuredMatches) { for (const m of fileMatches) { ctx.report.violation({ message: "Do not use $` template literals — they hang on Windows. Use Bun.spawn instead.", file: m.file, line: m.line, fix: "Replace $`cmd args` with Bun.spawn(['cmd', 'args'], { stdout: 'pipe', stderr: 'pipe' })", }); } } }, }, }, } satisfies RuleSet; ``` ## When to use it When your project must run on multiple platforms and a specific API is known to fail on one of them. Also useful for banning deprecated APIs with known reliability issues. ## When not to use it When your project targets a single platform and the banned API works reliably there.