RepoPilot

sindresorhus/get-port

Get an available TCP port

Mixed

OpenSSF Scorecard says this is unmaintained

HealthyDependency

Permissive license, no critical CVEs, actively maintained — safe to depend on.

HealthyFork & modify

Has a license, tests, and CI — clean foundation to fork and modify.

HealthyLearn from

Documented and popular — useful reference codebase to read through.

MixedDeploy as-is

Scorecard "Branch-Protection" is 0/10; Scorecard "Token-Permissions" is 0/10

  • Concentrated ownership — top contributor handles 69% of recent commits
  • Scorecard: marked unmaintained (2/10)
  • Scorecard: default branch unprotected (0/10)
  • Last commit 8w ago
  • 21+ active contributors
  • MIT licensed
  • CI configured
  • Tests present

What would improve this?

  • Deploy as-is MixedHealthy if: bring "Branch-Protection" to ≥3/10 (see scorecard report)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Safe to depend on" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Safe to depend on
[![RepoPilot: Safe to depend on](https://repopilot.app/api/badge/sindresorhus/get-port?axis=dependency)](https://repopilot.app/r/sindresorhus/get-port)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card

This card auto-renders when someone shares https://repopilot.app/r/sindresorhus/get-port on X, Slack, or LinkedIn.

Ask AI about sindresorhus/get-port

Grounded in the actual source code. Pick a starter question or write your own.

Or write your own question →

Onboarding doc

Onboarding: sindresorhus/get-port

Generated by RepoPilot · 2026-06-19 · Source

🎯Verdict

WAIT — OpenSSF Scorecard says this is unmaintained

  • Last commit 8w ago
  • 21+ active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 69% of recent 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>

TL;DR

get-port is a lightweight Node.js utility that finds and returns an available TCP port number. It accepts optional preferences (specific ports or ranges via the portNumbers() helper) and can permanently reserve ports for long-running processes. The core capability is testing port availability across all local network interfaces or a specific host, with fallback to OS-assigned random ports. Extremely simple flat structure: index.js contains the entire implementation, index.d.ts provides TypeScript definitions, test.js is the test suite, and index.test-d.ts validates type definitions. No src/ directory, no build step, pure ES module export via package.json type: "module".

👥Who it's for

Node.js developers writing test suites and development servers who need deterministic or preferred port allocation without manual conflict detection. Specifically useful for framework authors (Express, Fastify, etc.) and CI/CD pipelines that spawn multiple services needing isolated ports.

🌱Maturity & risk

Production-ready. This is a single-file pure JavaScript library (index.js + TypeScript definitions) by prolific maintainer Sindre Sorhus, version 7.2.0, with comprehensive test coverage (test.js), TypeScript type tests (index.test-d.ts), and CI via GitHub Actions (main.yml). Active maintenance indicated by semantic versioning and structured test suite.

Very low risk. Zero production dependencies (only dev tooling: ava, tsd, xo), tiny surface area (single-digit file count), and no breaking changes expected given stable API design. Single maintainer (Sindre Sorhus) is a known risk, but the module's simplicity and popularity mitigate this. Node.js >=16 requirement is reasonable.

Active areas of work

Based on the provided metadata, the repo appears stable with no visible active work. Version 7.2.0 is the current release. The structure suggests maintenance mode rather than active feature development, which is appropriate for a mature utility with a complete feature set.

🚀Get running

git clone https://github.com/sindresorhus/get-port.git && cd get-port && npm install && npm test

Daily commands: npm test — runs xo linter, ava test suite, and tsd type checking. No dev server; this is a library with no runtime. Import and call getPort() in your application to use.

🗺️Map of the codebase

  • index.js — Core implementation of port discovery logic using Node.js net module; all port-finding behavior originates here.
  • index.d.ts — TypeScript type definitions for the public API; defines the contract that all consumers depend on.
  • package.json — Declares module type as ESM, exports structure, and Node.js version requirement (≥16); critical for compatibility.
  • test.js — Comprehensive test suite validating core functionality including preferred ports, port exclusion, and error cases.
  • readme.md — Documents all public APIs, usage patterns (single port, array, ranges), and the portNumbers helper function.
  • .github/workflows/main.yml — CI/CD pipeline that runs linting, unit tests, and TypeScript type-checking on every commit.

🧩Components & responsibilities

  • getPort(options) (Node.js net, Promise) — Main export; orchestrates port selection by checking preferred ports sequentially, then falls back to OS random assignment.
    • Failure mode: Should never fail in normal conditions; throws only on OS network errors. Always returns a valid port.
  • portNumbers(from, to) (Generator function) — Helper generator function; yields all integers in a range for use as preferred ports list.
    • Failure mode: Returns empty iterable if from > to; no error thrown.
  • Port availability check (Node.js net.Server, event listeners) — Tests if a given port can be bound by creating a net.Server and immediately closing it.
    • Failure mode: EADDRINUSE error indicates port unavailable; any other error is treated as network failure (retried or escalated).

🔀Data flow

  • User codegetPort(options) — Passes optional Options object with preferred ports and excluded ports
  • getPort()Node.js net module — Attempts to create and bind Server instances to candidate ports
  • Node.js net moduleOS kernel — Issues socket bind() syscalls; OS responds with success or EADDRINUSE
  • getPort()User code (Promise resolve) — Returns first available port number or random OS-assigned port

🛠️How to make changes

Add a new port-selection strategy (e.g., preferred port with custom fallback)

  1. Update index.d.ts to add new optional parameter to Options interface (index.d.ts)
  2. Implement strategy logic in the main getPort function in index.js (index.js)
  3. Add test cases covering the new strategy in test.js (test.js)
  4. Update readme.md with usage examples of the new strategy (readme.md)

Add support for UDP ports or other protocol

  1. Extend Options interface in index.d.ts with protocol parameter (index.d.ts)
  2. Modify index.js to handle net.Server creation for different protocol types (index.js)
  3. Add comprehensive test cases for the new protocol in test.js (test.js)

Refine port scanning performance or add filtering logic

  1. Modify the port validation loop in index.js to implement new filtering (index.js)
  2. Add performance-related test cases in test.js (test.js)
  3. Update type definitions if new options are needed in index.d.ts (index.d.ts)

🔧Why these technologies

  • Node.js net module — Provides cross-platform TCP socket binding; the only reliable way to check port availability without race conditions.
  • ECMAScript Modules (ESM) — Modern JavaScript standard; aligns with contemporary Node.js best practices and future-proofs the library.
  • TypeScript type definitions (.d.ts) — Enables IDE autocomplete and compile-time type safety for TypeScript consumers without requiring TypeScript compilation.
  • AVA test framework — Provides simple, concurrent test execution with minimal configuration overhead suitable for a single-function library.

⚖️Trade-offs already made

  • Use net.Server binding to test port availability instead of OS-level port scanning

    • Why: Binding is the only truly reliable method that accounts for reserved ports, conflicting services, and OS-specific behavior.
    • Consequence: Slight performance cost per port (socket creation/teardown) but zero false positives.
  • Synchronous port preference checking (sequential, not parallel)

    • Why: Simplifies logic and avoids race conditions where multiple ports might bind simultaneously.
    • Consequence: Checking 10 preferred ports takes ~10x longer than checking one, but user rarely specifies many preferences.
  • Return random OS-assigned port (port 0) as ultimate fallback rather than scanning high ranges

    • Why: OS assignment is guaranteed available; scanning large ranges becomes slow and complexity-prone.
    • Consequence: Caller gets unpredictable port number but guaranteed availability.

🚫Non-goals (don't propose these)

  • Does not reserve ports; returned port may become unavailable immediately after check (inherent to any port-finding logic).
  • Does not handle named services or port aliases; only numeric port numbers are supported.
  • Does not provide timeout or cancellation support for the port-finding operation.
  • Does not support Windows-only features like port proxying or special reserved ranges beyond standard OS behavior.

📊Code metrics

  • Avg cyclomatic complexity: ~3 — Single-function library with straightforward sequential logic: loop through ports, try to bind, return first success. No nested abstractions or complex algorithms.
  • Largest file: index.js (120 lines)
  • Estimated quality issues: ~0 — Library passes xo linter, ava tests, and tsd type checks in CI. Code is intentionally simple with no complex dependencies or edge cases to manage.

⚠️Anti-patterns to avoid

  • Implicit race condition in port availability (Medium)index.js - between availability check and actual port use: Port confirmed available by getPort() may be claimed by another process before caller binds to it. This is inherent to the problem domain but worth documenting.
  • No timeout on socket operations (Low)index.js - net.Server event listeners: If OS hangs on socket binding (rare but possible on some systems), getPort() could block indefinitely. No timeout is set on the operation.

🔥Performance hotspots

  • index.js - preferred ports loop (I/O latency (socket binding overhead)) — Sequential checking of preferred ports; if 100 ports are provided and all are in use, 100 socket binds occur serially (~100-200ms).
  • index.js - fallback to random port (port 0) (Unavoidable per-call overhead) — If preferred port strategy exhausts all options, system must still allocate and teardown a socket for the random port, adding ~5-10ms.

🪤Traps & gotchas

No hidden traps detected. The module has zero runtime dependencies, making it immune to supply-chain risk. The reserve option creates a global lock per process (not per-host), which is correctly documented but easy to misunderstand. OS port availability is checked against all interfaces by default unless host is specified—ensure test isolation if running many instances.

🏗️Architecture

💡Concepts to learn

  • chalk/chalk — Complementary Sindre Sorhus utility often paired with get-port for colored console output in dev servers and test runners.
  • libuv/libuv — The underlying system library Node.js uses for net socket and port binding operations that get-port wraps.
  • avajs/ava — Test framework used in this repo; most users of get-port also use AVA for test isolation and port management.
  • expressjs/express — Popular Node.js web framework whose users commonly need dynamic port allocation for testing via get-port.
  • portfinder/portfinder — Direct competitor/alternative with similar functionality but lower maintenance; often referenced when comparing port-finding solutions.

🪄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 integration tests for edge cases in port selection logic

The test.js file likely covers happy paths, but edge cases like handling of reserved ports, ports already in use during fallback scenarios, and behavior when all preferred ports are unavailable need explicit coverage. This ensures robustness when users provide preferred port arrays or ranges.

  • [ ] Add test cases in test.js for simultaneous port binding scenarios
  • [ ] Add test cases for reserved/system ports (ports < 1024) behavior
  • [ ] Add test cases for portNumbers() helper with overlapping ranges
  • [ ] Add test cases verifying fallback behavior when all preferred ports are in use

Add TypeScript generics and stricter type definitions for port options

The index.d.ts file could benefit from more precise type safety. Currently, the port option likely accepts number | number[], but could use discriminated unions, branded types for valid port ranges (1-65535), and clearer return type documentation to prevent runtime errors from invalid port values.

  • [ ] Update index.d.ts to add branded type for valid port numbers (1-65535)
  • [ ] Add type overloads for getPort(options) supporting both single port and port array scenarios
  • [ ] Add JSDoc comments with @throws documentation for invalid port ranges
  • [ ] Add corresponding tsd tests in index.test-d.ts to validate type narrowing

Add Node.js version compatibility and platform-specific behavior tests

With engines requiring Node >=16, there may be platform-specific behaviors (Windows vs Unix socket handling, IPv6 support) that aren't explicitly tested. A dedicated workflow or test suite section would validate compatibility and document platform differences.

  • [ ] Add test cases in test.js for IPv6 port availability detection
  • [ ] Add test cases for behavior differences on Windows vs Unix platforms
  • [ ] Document any platform-specific port range limitations in index.d.ts JSDoc
  • [ ] Consider adding a test matrix in .github/workflows/main.yml for multiple Node versions and OS combinations

🌿Good first issues

  • Add explicit test coverage for IPv6-only hosts: the host option supports both IPv4 and IPv6 addresses per the README, but test.js does not show IPv6 address test cases (e.g., '::1'). Add AVA tests validating portNumbers with ipv6Only scenario.
  • Document clearLockedPorts() usage pattern in README with concrete example: the API exists and is tested, but the README only briefly mentions it in a truncated section. Add a code example showing when/why to call it in test teardown.
  • Add performance benchmark or guide: no documentation on port-checking performance with large portNumbers() ranges or many excluded ports. Create a simple benchmark script showing typical latency for different option combinations.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • efbebfb — 7.2.0 (sindresorhus)
  • 8af215b — Add reserve option 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 — Add clearLockedPorts() 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 a strong security posture. It is a minimal, focused utility with no external runtime dependencies (only dev dependencies), which significantly reduces the attack surface. The codebase follows modern JavaScript best practices (ESM module, strict linting via xo). No hardcoded secrets, injection vulnerabilities, or critical misconfigurations were identified. The minor vulnerabilities noted relate to dependency management practices and input validation documentation rather than active security flaws. Overall, this is a well-maintained, low-risk package suitable for production use.

  • Low · Outdated TypeScript Types Dependency — package.json - devDependencies. @types/node version ^20.2.5 is pinned to a specific minor version. While this is intentional for stability, security patches in Node.js type definitions may not be automatically applied if a newer patch is released within the same minor version range. Fix: Monitor @types/node for security updates and consider using a more flexible versioning strategy (e.g., ^20.0.0) or regularly audit dependencies with 'npm audit'.
  • Low · No Package Lock File Visible — Repository root. The presence of a lock file (package-lock.json or yarn.lock) is not indicated in the provided file structure. Without a lock file, dependency versions may vary between installations, potentially introducing inconsistent or vulnerable versions. Fix: Ensure package-lock.json is committed to version control and used consistently across all installations. Run 'npm ci' in CI/CD pipelines instead of 'npm install'.
  • Low · Limited Input Validation Guidance — Documentation and potential index.js implementation. Based on the README, the package accepts port numbers and arrays of port numbers as input. There is no visible documentation about validation bounds or error handling for edge cases (e.g., invalid port ranges, negative numbers, ports > 65535). Fix: Implement strict input validation for port numbers (0-65535 range), array bounds checking, and clear error messages for invalid inputs.

LLM-derived; treat as a starting point, not a security audit.

🤖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:

  1. 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.
  2. 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.
  3. 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.

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 ≤ 84 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>sindresorhus/get-port</code></summary>
#!/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 84 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~54d)"
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).

</details>

Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Embed this chat in your README →

Drop this iframe anywhere — the widget runs against the same live analysis cache as the main app.

<iframe
  src="https://repopilot.app/embed/sindresorhus/get-port"
  width="100%" height="500"
  style="border:1px solid #d0d7de; border-radius:8px;"
  allow="microphone"
  loading="lazy"
></iframe>