fkill
Fabulously kill processes by PID, name, or port — one cross-platform API for macOS, Linux, and Windows.
Repository Health
Technical Analysis
fkill is a small Node.js library for killing processes by PID, process name, or port number, with a single cross-platform API that works identically on macOS, Linux, and Windows. Instead of writing separate kill/taskkill/pkill shell-out logic for each platform, callers invoke one fkill() function and it handles process resolution, signal selection, and Windows’ taskkill peculiarities under the hood.
Beyond basic termination, it supports force-killing, waiting for a process to actually exit, escalating to a force-kill after a timeout, and killing by port by resolving the owning PID first. It’s maintained by Sindre Sorhus as part of a widely used ecosystem of small, focused npm utilities, and is the library underlying the fkill-cli command-line tool and the alfred-fkill Alfred workflow.
What You Get
- Cross-platform process termination - one
fkill()call resolves to the right OS-native kill mechanism (kill/pkillon POSIX,taskkillon Windows). - Port-to-PID resolution - pass a port prefixed with
:(e.g.:8080) and fkill looks up and kills the process bound to it viapid-port. - Force-kill and timeout escalation -
forcesends SIGKILL immediately;forceAfterTimeoutwaits, then escalates if the process hasn’t exited. - Exit confirmation -
waitForExitpolls until the process is confirmed gone (viaprocess-exists) instead of returning as soon as the kill signal is sent. - Batch killing with aggregated errors - accepts a single input or an array, kills them concurrently, and throws an
AggregateErrordescribing every failure rather than stopping at the first.
Common Use Cases
- Killing a dev server left on a port - a CLI tool or test runner calls
fkill(':3000')to free a port before restarting a server. - Cleaning up child/background processes in scripts - build tools and process managers use fkill to reliably terminate spawned Node or native processes across platforms.
- Graceful-then-forceful shutdown - a supervisor calls
fkill(pid, {waitForExit: 5000})to ask nicely first, then relies onforceAfterTimeoutto guarantee termination. - Killing processes by name in test suites - test fixtures spin up named processes and use
fkill('processName')in teardown instead of writing OS-specific cleanup code.
Under The Hood
Architecture
fkill is a single-file library (index.js, roughly 330 lines) exporting one default async function. It dispatches to platform-specific kill implementations (windowsKill, macosKill, and a default POSIX kill) based on process.platform, chosen via a small branch at call time rather than class-based polymorphism. Input normalization — including resolving ports to PIDs via pid-port — happens once upfront in the exported fkill() function; per-input handling then wraps the platform kill with special-casing for the node process name (killing sibling Node processes while explicitly excluding ancestors of the current process, computed via ps-list output) so a script can’t kill itself or its own process tree. Errors from concurrent kills are collected and thrown together as a single AggregateError rather than failing fast, and an optional forceAfterTimeout loop re-checks liveness with exponentially backed-off polling before escalating to a forced kill. There’s no dependency injection or class hierarchy — it’s a flat functional module — so swapping any OS-specific kill primitive (taskkill, pkill/kill, execa) is isolated to its own function.
Tech Stack
Plain Node.js (ES modules, engines >=20) with no framework dependencies. Runtime deps: execa for shelling out, taskkill for Windows process termination, pid-port for port-to-PID resolution, process-exists for liveness checks, and ps-list for enumerating processes (used only for the special node-name handling). Dev tooling: xo (an opinionated ESLint config) for linting, Node’s built-in node:test runner (no Jest/Mocha), tsd for type-testing the shipped .d.ts, and delay/get-port/noop-process as test-only helpers. There is no build step — it ships plain ES module JS with a hand-written index.d.ts.
Code Quality
test.js provides comprehensive coverage: pid-based kill, name/title-based kill, case-insensitivity, port-based kill, force kill, forceAfterTimeout escalation, waitForExit, silent mode, and batch/array input, using Node’s native node:test plus a noop-process helper for spawnable no-op test targets, with platform-conditional test blocks for Windows versus POSIX behavior. Error handling is explicit throughout — AggregateError with descriptive per-input messages, and a friendly “doesn’t seem to be installed” error when a required binary is missing — rather than swallowed. The implementation itself is plain JS, but the public API is fully typed via a hand-maintained index.d.ts checked against real usage with tsd. Naming is consistent and descriptive, and CI runs via GitHub Actions with xo enforcing lint rules alongside the test suite.
API Design
The public surface is a single function with sane defaults — no class to instantiate, no setup — call fkill(pid | name | ':port' | array, options?) and get a promise back. Killing by port is transparent: there’s no separate lookup step, fkill resolves the PID itself. Platform-appropriate defaults (force: false, tree: true on Windows) mean most calls need no options at all, while power users get escalation (forceAfterTimeout) and confirmation (waitForExit) as explicit opt-ins. Errors are aggregated into human-readable messages instead of raw OS error codes bubbling up. The tradeoff is a single overloaded input type (number | string | array) requiring runtime type-sniffing rather than distinct methods, but that keeps call sites extremely terse — clearly the design’s intent.
Used by 2 apps in this directory
Continue
Developer Tools · AI Development · AI Code Assistants
Open-source coding agent for VS Code, JetBrains, and CLI with support for 30+ LLM providers.
Notesnook
Note Taking · File Storage · Security
End-to-end encrypted, open-source note-taking where your data stays yours — even from the server.