get-port vs detect-port vs portfinder: Port Detection Utilities in Node.js (2026)
TL;DR
get-port is the minimal port finder — gets a random available port or checks specific ports, tiny (no dependencies), async, by Sindre Sorhus. detect-port is Alibaba's port detector — finds an available port starting from a preferred number, used by Umi and Egg.js, returns the next free port. portfinder is the classic port finder — scans from a base port upward, callback and promise API, the most widely used. In 2026: get-port for minimal port detection, detect-port for auto-incrementing port fallback, portfinder for legacy projects.
Key Takeaways
- get-port: ~10M weekly downloads — minimal, random or specific, by Sindre Sorhus
- detect-port: ~10M weekly downloads — Alibaba, auto-increment, fallback port
- portfinder: ~10M weekly downloads — classic, base port scanning, callback/promise
- All three find available TCP ports on localhost
- get-port is the most modern (ESM-only, no dependencies)
- detect-port and portfinder scan upward from a preferred port
get-port
get-port — minimal port finder:
Basic usage
import getPort from "get-port"
// Get a random available port:
const port = await getPort()
console.log(port) // → 52741 (random available port)
// Prefer a specific port, fallback to random:
const port2 = await getPort({ port: 3000 })
console.log(port2) // → 3000 if available, or random
// Prefer from a list of ports:
const port3 = await getPort({ port: [3000, 3001, 3002] })
console.log(port3) // → First available from list, or random
Port range
import getPort, { portNumbers } from "get-port"
// Get port from a range:
const port = await getPort({ port: portNumbers(3000, 3100) })
console.log(port) // → First available in 3000-3100, or random
// Use in a dev server:
import express from "express"
const app = express()
const port = await getPort({ port: portNumbers(3000, 3010) })
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`)
})
Make a range of ports
import getPort, { portNumbers } from "get-port"
// portNumbers returns an iterable:
const ports = portNumbers(8000, 8100)
const port = await getPort({ port: ports })
// Exclude specific ports:
const port2 = await getPort({
port: portNumbers(3000, 3100),
exclude: [3001, 3005],
})
// Host-specific:
const port3 = await getPort({
port: 3000,
host: "0.0.0.0", // Check on all interfaces
})
Dev server pattern
import getPort, { portNumbers } from "get-port"
import { createServer } from "node:http"
async function startServer() {
const port = await getPort({ port: portNumbers(3000, 3010) })
const server = createServer((req, res) => {
res.end("Hello!")
})
server.listen(port, () => {
console.log(`→ http://localhost:${port}`)
})
return { server, port }
}
detect-port
detect-port — auto-increment port:
Basic usage
import detect from "detect-port"
// Find available port starting from 3000:
const port = await detect(3000)
console.log(port)
// → 3000 if available
// → 3001 if 3000 is taken
// → 3002 if 3001 is also taken
// → etc.
// Default (starts from 1):
const port2 = await detect()
With callback
import detect from "detect-port"
// Callback style:
detect(3000, (err, port) => {
if (err) {
console.error(err)
return
}
if (port === 3000) {
console.log("Port 3000 is available")
} else {
console.log(`Port 3000 is taken, using ${port} instead`)
}
})
User prompt pattern
import detect from "detect-port"
import readline from "readline"
async function getServerPort(preferred: number): Promise<number> {
const available = await detect(preferred)
if (available === preferred) {
return preferred
}
// Port is taken — ask user:
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
})
return new Promise((resolve) => {
rl.question(
`Port ${preferred} is in use. Use ${available} instead? (Y/n) `,
(answer) => {
rl.close()
resolve(answer.toLowerCase() === "n" ? preferred : available)
}
)
})
}
// Usage:
const port = await getServerPort(3000)
// → "Port 3000 is in use. Use 3001 instead? (Y/n)"
CLI usage
# CLI:
npx detect-port 3000
# → 3000 (if available)
# → 3001 (if 3000 is taken)
# Check specific port:
npx detect-port 8080
portfinder
portfinder — classic port scanner:
Basic usage
import portfinder from "portfinder"
// Find available port (default starts at 8000):
const port = await portfinder.getPortPromise()
console.log(port) // → 8000 (or next available)
// Start from specific port:
const port2 = await portfinder.getPortPromise({ port: 3000 })
console.log(port2) // → 3000 or next available
// With options:
const port3 = await portfinder.getPortPromise({
port: 3000,
stopPort: 3100, // Don't scan beyond 3100
host: "127.0.0.1",
})
Callback style
import portfinder from "portfinder"
// Set base port:
portfinder.basePort = 3000
// Set highest port to scan:
portfinder.highestPort = 3100
portfinder.getPort((err, port) => {
if (err) {
console.error("No available port found:", err)
return
}
console.log(`Available port: ${port}`)
})
Multiple ports
import portfinder from "portfinder"
// Get multiple consecutive ports:
const ports = await portfinder.getPortPromise({ port: 3000 })
.then(async (port1) => {
const port2 = await portfinder.getPortPromise({ port: port1 + 1 })
return [port1, port2]
})
console.log(ports) // → [3000, 3001] (or next available pair)
With dev servers
import portfinder from "portfinder"
import { createServer } from "vite"
async function startViteDev() {
const port = await portfinder.getPortPromise({ port: 5173 })
const server = await createServer({
server: { port },
})
await server.listen()
console.log(`Vite dev server: http://localhost:${port}`)
}
Feature Comparison
| Feature | get-port | detect-port | portfinder |
|---|---|---|---|
| API style | Promise | Promise + callback | Promise + callback |
| Default behavior | Random port | Scan from preferred | Scan from 8000 |
| Port range | ✅ (portNumbers) | ❌ | ✅ (stopPort) |
| Exclude ports | ✅ | ❌ | ❌ |
| Host option | ✅ | ✅ | ✅ |
| CLI | ❌ | ✅ | ❌ |
| ESM-only | ✅ | ❌ | ❌ |
| Dependencies | 0 | 1 | 2 |
| TypeScript | ✅ | ✅ | ✅ (@types) |
| Maintained | ✅ (Sindre Sorhus) | ✅ (Alibaba) | ⚠️ |
| Weekly downloads | ~10M | ~10M | ~10M |
When to Use Each
Use get-port if:
- Want a minimal, zero-dependency port finder
- Need random port assignment or port ranges
- Building modern ESM projects
- Want to exclude specific ports
Use detect-port if:
- Want auto-incrementing port fallback (3000 → 3001 → 3002)
- Need a CLI for quick port checks
- Building tools where user confirmation of port change is needed
- In the Alibaba/Egg.js ecosystem
Use portfinder if:
- Need legacy callback support
- Want configurable port scan range (base + stop)
- Existing project already uses it
- Need a battle-tested port finder
Methodology
Download data from npm registry (weekly average, February 2026). Feature comparison based on get-port v7.x, detect-port v2.x, and portfinder v1.x.
Compare networking utilities and developer tooling on PkgPulse →