Lightweight cross-platform port termination for Node.js with programmatic APIs (portKill, portKillSync) and CLI (port-kill), with zero runtime dependencies.
- Cross-platform support: Windows, macOS, Linux.
- Multi-port targeting in one command.
- Supports verbose logs, dry-run audits, force/graceful termination, and signal override.
- Safe defaults for dev/test/CI port cleanup workflows.
| Area | Support / Requirement | Notes |
|---|---|---|
| Node.js | >=16.0.0 |
Declared in package engines.node. |
| Windows | cmd.exe, PowerShell |
Uses netstat for PID discovery and taskkill for termination. |
| macOS | Terminal shells (zsh/bash) | Uses lsof with fuser fallback, and kill. |
| Linux | Terminal shells (bash/sh/zsh) | Uses lsof with fuser fallback, and kill. |
| Required system tools | lsof, fuser, kill (POSIX); netstat, taskkill (Windows) |
Must be available in PATH. |
- Killing processes on protected/privileged ports (for example
80,443) may require elevated privileges. - On macOS/Linux this can require
sudo. - On Windows this can require an elevated Administrator shell.
- Without required privileges, commands can fail for those ports and return a non-zero CLI exit code.
Local (project/test workflows):
npm install --save-dev @gks101/port-kill
yarn add -D @gks101/port-kill
pnpm add -D @gks101/port-killGlobal CLI install (optional):
npm install -g @gks101/port-killRun without install:
npx @gks101/port-kill 3000port-kill <ports...> [options]# Single port
port-kill 3000
# Multiple ports in one run
port-kill 3000 8080
# Multiple ports with logs
port-kill 3000 8080 --verbose
# Graceful signal on POSIX
port-kill 3000 8080 --no-force --signal SIGTERM| Flag | Alias | Type | Default | Description |
|---|---|---|---|---|
--help |
-h |
none | n/a | Show help and exit with code 0. |
--version |
-v |
none | n/a | Show version and exit with code 0. |
--verbose |
-d |
none | false |
Print verbose execution details. |
--dry-run |
none | none | false |
Discover PIDs without killing them. |
--force |
none | none | true |
Explicitly enforce aggressive termination mode. |
--no-force |
none | none | false (toggle) |
Disable force mode and use graceful termination behavior. |
--signal <sig> |
-s |
string | OS-derived (SIGKILL or SIGTERM) |
POSIX-only signal override (ignored on Windows). |
import { portKill, portKillSync } from '@gks101/port-kill';type PortKillSignal = 'SIGKILL' | 'SIGTERM' | 'SIGINT' | string;
interface PortKillOptions {
force?: boolean;
signal?: PortKillSignal;
verbose?: boolean;
dryRun?: boolean;
logger?: (message: string, level?: 'info' | 'warn' | 'error' | 'debug') => void;
}
interface PortKillResult {
port: number;
success: boolean;
pids: number[];
message: string;
error?: string;
timestamp: string;
}
declare function portKill(
ports: number | number[],
options?: PortKillOptions
): Promise<PortKillResult[]>;
declare function portKillSync(
ports: number | number[],
options?: PortKillOptions
): PortKillResult[];import { portKill, portKillSync } from '@gks101/port-kill';
const asyncResults = await portKill([3000, 8080], {
verbose: true,
force: true,
});
const syncResults = portKillSync([3000, 8080], {
force: false,
signal: 'SIGTERM',
});- If a port is already free (no active process found), operation is treated as success.
- Programmatic: returns
success: truefor that port. - CLI: prints
Already freeand keeps exit code0(unless another targeted port fails).
- Programmatic: returns
- CLI returns exit code
1for parse errors, invalid signals, invalid ports, permission failures, or kill failures.
If you chain with &&, later commands run only when port-kill exits with 0.
port-kill 3000 8080 && npm run devUse this when you want hard-stop behavior. If you want dev server boot to continue even if cleanup fails, use an alternative chain strategy in your shell.
- PID lookup and kill are separate OS calls, so a TOCTOU race window can exist on high-churn hosts.
- System binaries are resolved from
PATH(lsof,fuser,netstat,kill,taskkill). - Prefer trusted runtime environments; use elevated privileges only when needed.
Apache-2.0