sindresorhus/get-port
Get an available TCP port
Single-maintainer risk — review before adopting
worst-casePermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
Scorecard "Branch-Protection" is 0/10; Scorecard "Token-Permissions" is 0/10
- ✓Last commit 6w ago
- ✓5 active contributors
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
- ⚠Small team — 5 top contributors
- ⚠Single-maintainer risk — top contributor 89% of commits
- ⚠Scorecard: marked unmaintained (2/10)
- ⚠Scorecard: default branch unprotected (0/10)
What would change the verdict?
- →Deploy as-is WAIT → GO if: bring "Branch-Protection" to ≥3/10 (see scorecard report)
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard
Embed this verdict
[](https://repopilot.app/r/sindresorhus/get-port)Paste into your README — the badge live-updates from the latest cached analysis.
Onboarding doc
Onboarding: sindresorhus/get-port
Generated by RepoPilot · 2026-05-05 · Source
Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/sindresorhus/get-port shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
Verdict
WAIT — Single-maintainer risk — review before adopting
- Last commit 6w ago
- 5 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Small team — 5 top contributors
- ⚠ Single-maintainer risk — top contributor 89% of commits
- ⚠ Scorecard: marked unmaintained (2/10)
- ⚠ Scorecard: default branch unprotected (0/10)
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard</sub>
Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live sindresorhus/get-port
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/sindresorhus/get-port.
What it runs against: a local clone of sindresorhus/get-port — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in sindresorhus/get-port | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 74 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of sindresorhus/get-port. If you don't
# have one yet, run these first:
#
# git clone https://github.com/sindresorhus/get-port.git
# cd get-port
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of sindresorhus/get-port and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "sindresorhus/get-port(\\.git)?\\b" \\
&& ok "origin remote is sindresorhus/get-port" \\
|| miss "origin remote is not sindresorhus/get-port (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "index.js" \\
&& ok "index.js" \\
|| miss "missing critical file: index.js"
test -f "index.d.ts" \\
&& ok "index.d.ts" \\
|| miss "missing critical file: index.d.ts"
test -f "package.json" \\
&& ok "package.json" \\
|| miss "missing critical file: package.json"
test -f "test.js" \\
&& ok "test.js" \\
|| miss "missing critical file: test.js"
test -f "readme.md" \\
&& ok "readme.md" \\
|| miss "missing critical file: readme.md"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 74 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~44d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/sindresorhus/get-port"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
TL;DR
get-port is a lightweight Node.js utility that finds and returns an available TCP port on the system. It supports preferred port selection (single or array), port ranges via the portNumbers() helper, exclusion lists, optional port reservation for long-running processes, and host-specific availability checking. Core use: getPort({port: 3000}) returns port 3000 if free, otherwise a random available port. Simple flat structure: index.js is the main implementation, index.d.ts provides TypeScript types, index.test-d.ts validates types, test.js contains integration tests. No monorepo or complex layering—pure single-package design emphasizing simplicity and zero-dependency footprint.
Who it's for
Node.js developers building development servers, test runners, and CLI tools who need to dynamically allocate ports without conflicts—particularly test suite authors using Jest/AVA and framework developers (Express, Fastify) running multiple processes simultaneously.
Maturity & risk
Production-ready and actively maintained. At v7.2.0 with comprehensive test coverage (test.js + TypeScript definitions in index.test-d.ts), full CI/CD via GitHub Actions (main.yml workflow), and a mature ESM module structure. Sindre Sorhus is a well-respected maintainer with consistent updates; no signs of abandonment.
Very low risk: zero production dependencies (sideEffects: false), minimal surface area (12KB JavaScript + 538B TypeScript types), and Node 16+ only requirement is well-supported. Single-maintainer risk exists but Sorhus projects have high community trust. No breaking changes visible in package.json history shown.
Active areas of work
No specific commit or PR data visible in file structure, but the project is maintained (v7.2.0 exists with xo linting, AVA testing, and tsd type checking all wired into npm scripts). Likely in steady-state maintenance mode with occasional security/dependency updates.
Get running
git clone https://github.com/sindresorhus/get-port.git
cd get-port
npm install
npm test
Daily commands:
This is a library, not an executable. Test it: npm test runs xo (linter), ava (tests), and tsd (type checking). To use locally: import getPort from './index.js' and call getPort({port: 3000}).
Map of the codebase
index.js— Core entry point implementing the port discovery algorithm; all port detection logic and OS integration lives here.index.d.ts— TypeScript type definitions for the public API; required for type-safe consumer code.package.json— Defines ESM export, Node.js version requirement (16+), and test scripts that validate the codebase.test.js— Integration tests covering the main use cases (single port, port arrays, exclusions, edge cases).readme.md— User-facing API documentation with examples for preferred ports, port ranges, and the portNumbers() helper.
Components & responsibilities
- getPort(options?) (JavaScript async functions, Node.js Net module) — Main entry point that orchestrates preferred port checking and fallback to random port selection
- Failure mode: Throws if no available port found (should not occur on normal systems)
- checkPort(port) (Node.js Net.createServer, error handling) — Validates if a specific TCP port is available by attempting to bind a server
- Failure mode: Returns false if port is in use or inaccessible; suppresses EADDRINUSE errors
- portNumbers(from, to) (JavaScript generators) — Generator helper that yields a range of port numbers for preferred port iteration
- Failure mode: None; pure utility function
Data flow
Caller→getPort()— Input options object with optional preferred ports and exclusion listgetPort()→checkPort()— Candidate port number to validatecheckPort()→Node.js Net API— Attempt to bind server on given portNode.js Net API→checkPort()— Success/EADDRINUSE error responsecheckPort()→getPort()— Boolean availability statusgetPort()→Caller— Available port number as Promise resolution
How to make changes
Add support for a new preferred port configuration option
- Add the new option field to the TypeScript interface in index.d.ts under the options type (
index.d.ts) - Implement the option handling logic in the getPort() function in index.js (
index.js) - Add test cases in test.js to verify the new option works correctly (
test.js)
Modify port availability checking behavior
- Update the checkPort() helper function logic in index.js that validates if a port is available (
index.js) - Add corresponding test cases to test.js covering the new behavior (
test.js) - Update type definitions in index.d.ts if the change affects the public API surface (
index.d.ts)
Add a new helper function (like portNumbers)
- Implement the helper function in index.js and export it as a named export (
index.js) - Add TypeScript type definition for the helper in index.d.ts (
index.d.ts) - Document the helper with usage examples in readme.md (
readme.md) - Add test cases in test.js to verify the helper's behavior (
test.js)
Why these technologies
- Node.js Net module — Provides OS-level TCP socket binding required to detect port availability without race conditions
- ESM (ES Modules) — Modern JavaScript module system that enables tree-shaking and is the default for Node.js 16+
- TypeScript definitions — Provides type safety for consumers in TypeScript projects without adding compilation overhead
- AVA test runner — Lightweight test framework with async/await support for testing Promise-based port discovery
Trade-offs already made
-
Use server binding (create and close) instead of port scanning
- Why: Avoids race conditions where a port becomes available between check and use
- Consequence: Slightly slower but more reliable; eliminates TOCTOU vulnerabilities
-
No built-in retry/backoff for preferred ports
- Why: Keeps API simple; users can implement custom retry logic if needed
- Consequence: Falls through to random port immediately; users lose preference if port unavailable
-
Support both single port and iterables
- Why: Allows flexible input (number, array, generator) without breaking changes
- Consequence: Slightly more complex normalization logic in getPort()
Non-goals (don't propose these)
- Does not support UDP or other non-TCP protocols
- Does not provide port reservation or locking mechanisms
- Does not support IPv6-specific port handling
- Does not include built-in retry/backoff strategies
- Does not manage or track port lifecycle after discovery
Code metrics
- Avg cyclomatic complexity: ~2 — Simple linear iteration over preferred ports followed by random fallback; no nested loops or complex conditionals
- Largest file:
index.js(120 lines) - Estimated quality issues: ~0 — Well-maintained library with consistent style, comprehensive tests, and TypeScript definitions; passes xo linter
Anti-patterns to avoid
- No explicit error handling for edge cases (Low) —
index.js: Silent fallback to random port if no preferred ports work; no warning logged to user about preferred port unavailability - Potential TOCTOU race on port selection (Medium) —
index.js: Time-of-check to time-of-use window exists between checkPort() validation and actual server binding by caller; mitigation is caller's responsibility
Performance hotspots
index.js - checkPort() iteration(I/O bound) — Sequential port checking; each preferred port requires a new server binding and socket close cycle (~10-50ms per port)index.js - Random port selection(Retry logic) — Fallback to random port generation and checking if all preferred ports fail; no exponential backoff or caching of previously validated ports
Traps & gotchas
No required environment variables or external services. Key gotcha: the reserve option locks ports globally for the process lifetime—call clearLockedPorts() between independent test runs or tests may fail with 'port already in use' despite calling getPort() fresh. Port availability checking is OS-dependent; Windows vs. Linux vs. macOS behavior may differ slightly when checking specific hosts.
Architecture
Concepts to learn
- TCP port binding and availability checking — get-port's core task is polling the OS to find unbound TCP ports; understanding how Node's net module detects port conflicts is essential to modify the scanning logic.
- Process-level global state and locking — The
reserveoption locks ports globally within a single Node process; understanding global state patterns and clearLockedPorts() is critical to use reserved ports correctly without test contamination. - ES Modules and dual package exports — This project uses type: 'module' and exports both a default export (getPort) and named export (portNumbers); understanding ESM syntax and package.json exports field is needed to extend the API.
- TypeScript type narrowing with Iterable<T> — The
portoption accepts number | Iterable<number>, and index.d.ts uses Iterable to support arrays, generators, and custom iterables—understanding this enables adding flexible new parameter types. - Host-specific TCP availability (IPv4 vs. IPv6) — The
hostparameter allows checking port availability on specific addresses; understanding how Node's net module handles IPv4, IPv6, and dual-stack sockets affects port resolution behavior. - Promise-based async API patterns — All get-port APIs return Promises; understanding async/await, error propagation, and Promise composition is essential to use the library and extend it with new options.
Related repos
libuv/libuv— Low-level C library that Node.js net module wraps for socket/port operations—understanding libuv helps debug platform-specific port availability edge cases.nodejs/node— Node.js core; get-port depends on net module behavior—useful for understanding TCP port binding semantics and OS integration.avajs/ava— Test runner used in this project (npm test calls ava)—learning AVA patterns helps understand and extend the test.js suite.xojs/xo— Linter used in CI (npm test calls xo)—enforces code style; understanding xo config helps avoid lint failures on contributions.bnoordhuis/node-portfinder— Alternative port-finding library with similar goal but different API; comparison helps understand design trade-offs in get-port's minimalist approach.
PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive error handling and edge case tests in test.js
The test.js file likely lacks coverage for edge cases such as: ports outside valid range (0-65535), attempting to use reserved ports, concurrent port requests, and handling system-level port binding failures. These tests would improve robustness and help catch regressions in port allocation logic.
- [ ] Add test cases in test.js for invalid port numbers (negative, >65535)
- [ ] Add test cases for rapid concurrent getPort() calls to verify no race conditions
- [ ] Add test cases for system-reserved ports (1-1024) behavior
- [ ] Add test cases for timeout/error scenarios when ports cannot be allocated
- [ ] Verify all new tests pass with
npm test
Document the complete options object schema in index.d.ts and readme.md
The README shows basic usage but the TypeScript definitions in index.d.ts likely contain additional options (like timeout, host, or exclusion lists) that aren't documented. Adding comprehensive JSDoc comments to index.d.ts and expanding the API section in readme.md would help users discover all available features.
- [ ] Review index.d.ts to identify all available options beyond 'port'
- [ ] Add JSDoc comments to index.d.ts for each option parameter
- [ ] Expand the 'API' section in readme.md with complete options documentation including types and defaults
- [ ] Add usage examples for any undocumented options
- [ ] Run
npm testto ensure type definitions are valid
Add integration tests for cross-platform port binding behavior in test.js
The current test suite may not adequately verify behavior differences across Windows, macOS, and Linux regarding port availability checks and TCP/UDP socket handling. Adding platform-specific integration tests would ensure get-port works reliably across all supported Node.js environments.
- [ ] Add tests in test.js that verify port binding on the actual OS (not mocked)
- [ ] Add tests for IPv4 vs IPv6 port availability detection
- [ ] Add tests to verify behavior when the same port is requested by multiple processes
- [ ] Optionally add test.js skip conditions for platform-specific tests where applicable
- [ ] Verify all tests pass with
npm teston Windows, macOS, and Linux
Good first issues
- Add explicit tests for the
excludeoption with edge cases (excluding all preferred ports, excluding ports in portNumbers() range)—test.js has basic coverage but boundary conditions are untested. - Document the
hostparameter behavior more clearly with examples showing IPv4 vs. IPv6 address handling in README.md—currently vague about how host filtering interacts with OS network interfaces. - Add a helper function or example showing how to reserve a port and then bind a server to it reliably—clarify the gap between
getPort({reserve: true})and actual server binding in docs.
Top contributors
- @sindresorhus — 48 commits
- @jonahsnider — 2 commits
- @nagen010 — 2 commits
- @nanianlisao — 1 commits
- @SamVerschueren — 1 commits
Recent commits
efbebfb— 7.2.0 (sindresorhus)8af215b— Addreserveoption to lock ports for the process lifetime (sindresorhus)c401d13— Clarify race condition protections in docs (sindresorhus)5c3cfe8— 7.1.0 (sindresorhus)cacb5f2— Meta tweaks (sindresorhus)d4fb7f8— AddclearLockedPorts()method (#70) (nanianlisao)85c1867— 7.0.0 (sindresorhus)5cc3422— Require Node.js 16 (sindresorhus)bd8a403— Use timeout instead of interval for releasing ports (#68) (SamVerschueren)0760c98— 6.1.2 (sindresorhus)
Security observations
The get-port package demonstrates good security posture. It is a minimal, focused utility with no production dependencies, reducing the attack surface. The codebase shows no obvious injection vulnerabilities, hardcoded secrets, or critical misconfigurations. Primary concerns are the minimum Node.js version being below actively maintained LTS releases and flexible dev dependency versioning. The package follows security best practices with proper module exports, type definitions, and a comprehensive test suite. Overall security risk is low.
- Low · Permissive Node.js Engine Version —
package.json. The package.json specifies 'engines': {'node': '>=16'}, which allows Node.js 16 (EOL since September 2023). This could lead to users running the package on unsupported versions without security updates. Fix: Update the minimum Node.js version to at least 18 LTS or higher to ensure users are on actively maintained versions with security patches. - Low · Flexible Dependency Versions —
package.json - devDependencies. Dev dependencies use caret (^) versioning for @types/node, ava, tsd, and xo, which allows minor and patch updates. While this is common practice, it could theoretically introduce unexpected changes or security issues in transitive dependencies. Fix: Consider using more restrictive versioning (e.g., ~) for critical linting and testing tools, or lock versions in package-lock.json. Ensure npm audit is regularly run in CI/CD.
LLM-derived; treat as a starting point, not a security audit.
Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.